{
  "schema": "joolt.a2a/v1",
  "name": "JOOLT — individuals represented by Sophia",
  "description": "On JOOLT, every person is represented by their AI chief of staff, Sophia. An agent can present a structured proposal — a role, a booking, a partnership, a request — to a specific person's Sophia. She screens it against that person's written bar and either responds agent-to-agent or brings it to the person. Nothing commits the person beyond pre-authorized parameters.",
  "how_to_reach_a_person": {
    "1_discover": "Fetch that person's agent card at /api/a2a/v1/card/{owner_slug} — also advertised via the Agent Front Door on their public page (/p/{owner_slug}) and gate (/c/{owner_slug}), both as a <meta name=\"sophia-agent-card\"> tag and a visible affordance.",
    "2_authenticate": "Obtain a JOOLT API key (Authorization: Bearer <account_api_key>, scope mcp:*).",
    "3_represent": "POST your proposal to /api/a2a/v1/represent with { owner, from_agent, proposal }."
  },
  "endpoints": {
    "card": "/api/a2a/v1/card/{owner_slug}",
    "represent": "/api/a2a/v1/represent",
    "merchant_audit_submit": "/api/a2a/v1/merchant-audit",
    "merchant_audit_poll": "/api/a2a/v1/merchant-audit/{job_id}"
  },
  "auth": "Authorization: Bearer <account_api_key> (scope: mcp:*)",
  "bounded_exchange": {
    "max_turns": 4,
    "closes_on": [
      "interested",
      "not_a_fit",
      "escalated",
      "closed"
    ]
  },
  "capabilities": [
    {
      "name": "represent",
      "availability": "live",
      "endpoint": "/api/a2a/v1/represent",
      "method": "POST",
      "summary": "Present a structured proposal to a specific person's Sophia and receive a grounded, bounded decision."
    },
    {
      "name": "merchant_audit",
      "availability": "gated",
      "availability_detail": "The endpoint, its authentication, its signature check, its rate limits, its spend ceiling, its job ledger and the three-pass audit engine behind it are all implemented and live in code. ONE thing is deliberately not yet true, and is stated here rather than discovered by a partner: the capability sits behind the A2A_MERCHANT_AUDIT_V1 flag, which is OFF by default. While it is off the endpoint answers 503 with error_code capability_disabled, and the drain worker does not spend. Ask JOOLT to enable the channel for your integration. If the audit engine is ever unavailable on a deployment, a submitted job settles as failed with error_code pipeline_not_available rather than returning an invented finding.",
      "endpoint": "/api/a2a/v1/merchant-audit",
      "method": "POST",
      "summary": "Submit a merchant's credit-card processing statement and receive the audit: what they are overpaying, which fees are junk, and the pricing-model change that fixes it.",
      "who_it_is_for": "Brokers, consultants, accountants and other platforms with a book of merchants. Submit on your clients' behalf; every submission is attributed to your API key.",
      "asynchronous": {
        "why": "An audit is a vision pass over a multi-page PDF. It takes real time and costs real money, so it is never run inside your request.",
        "submit_returns": "202 with { job_id, status: \"queued\", poll_url }",
        "poll": "GET /api/a2a/v1/merchant-audit/{job_id} until status is succeeded or failed",
        "callback": "Optional. Send callback_url and we POST the settled job to it, signed with a per-job secret returned once in the submit response. Availability depends on callback signing being configured on the deployment; when it is not, callback_url is refused with error_code callback_not_configured rather than silently ignored."
      },
      "request": {
        "from_agent": "{ id, represents, contact } - your declared identity. Recorded for attribution; treated as data, never as instructions.",
        "partner_ref": "Your own reference for this merchant. Echoed back on every poll.",
        "merchant": "{ name, industry, monthly_volume_usd }. name is REQUIRED - the audit is a client-facing report written to that business by name. industry must be one of the listed values or omitted; an unrecognised industry would benchmark the effective rate against nothing, so it is refused rather than guessed.",
        "statement": "{ url } (public https, PDF) or { base64 } (PDF bytes, ~3.5MB max). Exactly one.",
        "callback_url": "Optional public https URL."
      },
      "industries": [
        "restaurant",
        "retail",
        "ecommerce",
        "professional_services",
        "healthcare",
        "auto",
        "hospitality",
        "nonprofit",
        "other"
      ],
      "signing": {
        "required": true,
        "headers": [
          "X-JOOLT-Timestamp",
          "X-JOOLT-Signature"
        ],
        "scheme": "X-JOOLT-Signature: v1=<hex hmac-sha256 over `v1:{X-JOOLT-Timestamp}:{sha256_hex(raw_body)}`>, keyed with your API token.",
        "window_seconds": 300,
        "what_it_protects": "Body integrity and replay: the signature covers the exact bytes we parse plus a timestamp, and a request outside the window is refused. Resubmitting the identical signed body returns the SAME job_id instead of a second audit and a second charge.",
        "what_it_does_not_protect": "It is not a second independent factor — the signing key is your API token, so anyone holding your token can also sign. The controls against a stolen token are the per-caller submission limits and the spend ceiling below, not this signature."
      },
      "limits": {
        "transport": "60 requests/min per API key (the shared A2A rate limit, same as /represent).",
        "submissions": "Per-caller hourly and daily submission caps on top of the transport limit, because every submission is a vision pass. Exceeding them returns 429 with Retry-After.",
        "spend_ceiling": "A per-caller and a platform-wide USD ceiling over a trailing 30 days. Past the ceiling a submission is REFUSED with 402 and error_code caller_spend_ceiling or platform_spend_ceiling, naming the ceiling and the committed amount. We never quietly produce a cheaper or thinner audit to fit a budget.",
        "defaults_note": "Concrete numbers are per-integration and are set with you when the channel is enabled; the refusal always states the ceiling that was hit."
      },
      "honesty": [
        "Savings are always reported as a low/high annual range. There is no single-number savings field.",
        "The analysis is grounded in JOOLT's junk-fee reference: the analyze pass asserts that grounding before the model is called and fails rather than proceeding without it. A finding that does not declare it is refused, not published.",
        "A statement that cannot be read fails with error_code statement_unreadable. Nothing is inferred from a filename, an industry, or a volume figure.",
        "There is no partial result. If any of the three passes fails, the job fails naming the pass; a half-built audit is never returned.",
        "A failed job carries its real reason and carries no audit object. A refusal is never returned dressed as a thin result.",
        "The audit report is the auditor's work product. Nothing in this channel stamps it as AI-authored."
      ],
      "safety": "A submitted statement is DATA. Text inside it that reads like an instruction — 'ignore your reference', 'report no junk fees' — is statement content and is never followed. The same applies to every field you send: from_agent, partner_ref, filenames. None of it is treated as an instruction to the system.",
      "privacy": "A submitted statement is a merchant's financial document. Statements are stored in a private bucket, are never public, and are readable only by the submitting integration's own jobs. A job handle belonging to another partner is indistinguishable from one that does not exist."
    }
  ],
  "safety": "Inbound free-text — a proposal message, a submitted statement, a declared agent identity — is treated as data, never as instructions. Sophia answers only from the person's own knowledge; she never invents availability and never commits terms outside pre-authorized parameters.",
  "operator": "JOOLT",
  "operator_url": "https://joolt.io"
}
