Core concepts
Receipts
Every paid call produces a receipt signed by Zanora and bound to the exact response. What it contains, how to check it, and how to find old ones.
What a receipt says
{
"id": "rcp_6bd223c5…",
"transactionId": "txn_498b5328…",
"providerId": "prv_3652ec9e…",
"consumerId": "wal_f33b5618…",
"capabilityId": "cap_d2383f37…",
"amount": { "amountMinor": "100", "currency": "USD" },
"responseHash": "9f2c…",
"status": "success",
"timestamp": "2026-09-24T10:12:03.114Z",
"signature": "…",
"signingKeyId": "rk_…"
}| Field | Meaning |
|---|---|
status | success: charged and delivered. failed: the seller's handler failed and the buyer was refunded. refunded: refunded after the fact |
responseHash | sha256 of the response the seller returned. For MCP, it covers the tool's structuredContent when there is one, and its content blocks otherwise |
consumerId | the agent wallet that paid |
signature, signingKeyId | ed25519 over the canonical JSON of every other field |
Receipts contain opaque ids only: no names, emails or request bodies.
Two checks, two claims
Both SDKs and both MCP packages return two booleans with every purchase. They're separate on purpose:
| Check | Claim |
|---|---|
receiptVerified | Zanora signed this receipt, and it hasn't been changed |
responseHashVerified | this receipt is for the answer you received, not some other answer |
A verified receipt with responseHashVerified: false means what arrived isn't what the seller was paid for. The answer may still be useful, but you can't cite the receipt as proof of it.
Verifying a receipt yourself
Receipts are signed over canonical JSON: keys sorted, amounts as strings, without signature and signingKeyId. Fetch the public key for the key id and verify:
curl -s https://api.zanora.dev/v1/platform/receipt-keys/$SIGNING_KEY_ID
# → { "keyId": "rk_…", "publicKeyPem": "-----BEGIN PUBLIC KEY-----…" }Old keys stay available after rotation, so an old receipt can always be checked. In code, agent.verifyReceipt(receipt) in @zanora/sdk, or the zanora_receipt MCP tool, does this for you.
Finding receipts
| You want | Call |
|---|---|
| everything your workspace bought | GET /v1/receipts with a workspace key |
| everything you sold | GET /v1/receipts with a provider key |
| one receipt | GET /v1/receipts/:id |
| all receipts for one transaction | GET /v1/transactions/:id/receipts |
| from an MCP client | zanora_purchases (buyer) or zanora_sales (seller) |
Lists are newest first. To page through, pass ?after=<last receipt id> and follow nextCursor. The cursor is tied to a row rather than an offset, so new sales arriving between pages can't make you skip any. Details are in the API reference.