Receipt

A receipt is the one artefact Regent produces that is meant to leave Regent. It states what one decision authorised and what settled, under which signed terms and which policy version, and it verifies with a public key alone. An insurer, an auditor, a merchant in a dispute or a regulator checks it without an account, without calling Regent, and without trusting the operator of the agent.

This page is the specification. The verifiers that implement it are public: regent-receipt-verify (PyPI regent-receipt-verify, npm @regent-protocol/receipt-verify, Apache-2.0), with test vectors minted by the real issuer.

Shape

A receipt is a compact JWS (header.payload.signature), signed RS256 by Regent’s issuer.

HeaderValue
algRS256
typreceipt+jwt
kidthe signing key’s id, looked up in Regent’s JWKS

The JWKS is published at https://control-api.regentprotocol.org/v1/control/.well-known/jwks.json. Keys rotate; save the JWKS together with the receipts you keep, and pass the saved copy to the verifier later. Every JWKS you ever saved stays valid for the receipts minted under it.

Two other tokens share the issuer and the verifier: the allow token (aud = the tool, scope = tool:action, sixty seconds, the proof an agent carries to the rail) and the budget token (typ aa-auth+jwt, an AAuth budget envelope). The verifier names the kind it was given; a receipt can never pass as an access token, because its aud is the fixed string regent-receipt.

Claims

Always present:

ClaimMeaning
issregent-control
subthe agent’s agent_… identifier
audregent-receipt
jtithe receipt id, rcp_…
decision_idthe decision this receipt closes, dec_…
statussuccess or failed
iatwhen the receipt was issued
expten years after iat; the retention horizon, not a validity window for the facts

Present on money decisions:

ClaimMeaning
amount, currencywhat settled, in the purchase currency (a number and an ISO 4217 code or a token symbol)
payeethe counterparty: a merchant name, a store id, a chain address
payee_sourcewho named the payee: rail (read from the payment rail itself, never from the agent) or agent
payee_kindthe kind of counterparty when the rail says it (a connected account, a bank payout, a merchant)
mandate_idthe mandate the decision was taken under
mandate_version, mandate_hashthe version of the mandate’s terms in force, and a salted commitment to them (see Commitments)
tool, actionwhat the agent was doing: stripe / charge.create, agentcard_buy / POST /buy, custody / transfer
args_hasha commitment to the exact request the decision bound (see Commitments)
settlement_mismatchtrue when what settled differs from what was decided (a lower or higher amount, another payee)

Present when the organization uses them:

ClaimMeaning
policy_version, policy_hash, policy_sourcethe organization’s policy version in force and a salted commitment to it; policy_source is org, starter (Regent’s public starter policy; no reveal needed) or legacy
risk_modelthe behavioural model version that scored the request (guardian-1.2); the score itself is not in the receipt
approval_methodhow a person approved the terms or this escalation: passkey, passkey+authid (passkey plus a biometric step-up), or session in a sandbox
approval_digesta commitment to exactly what the person saw and signed
environmentproduction or sandbox; absent on receipts older than October 2026
assertion_scheme, assertion_kid, key_custodyhow the agent itself was authenticated: the signature scheme on its request, the key id, and whether that key is the agent’s own or held in custody for it
ap2_transaction_id, ap2_payment_referencethe references of the AP2 mandate chain emitted for this decision (AP2 Evidence)
agent_report_mismatchtrue when the agent’s own report of the outcome disagreed with what the rail confirmed

Present when the money’s outcome came from somewhere other than the agent:

ClaimMeaning
settlement_sourcewho the settlement facts came from: counterparty (the merchant or PSP signed a confirmation), provider (the rail reported the outcome), custodian (the custodian executed the transfer)
settlement_refthe rail’s own reference for the settled money: a chain transaction hash, a PSP charge id
settlement_networkthe chain the reference lives on, when it does
confirmed_by, confirmation_kid, confirmation_hash, confirmationthe counterparty’s signed settlement confirmation, embedded whole, with its issuer, key id and a hash over it

Claims are added over time; a verifier shows every claim it is given and checks the ones it knows. An absent claim means the fact was not available for that decision, never that it was false.

Commitments

Three claims are commitments: hashes a third party recomputes from material the owner reveals. The ceilings themselves never ride in a token.

args_hash: SHA-256 over the canonical JSON of {"tool", "action", "resource", "args"}, keys sorted, no whitespace (separators (",", ":")), UTF-8, non-ASCII kept as is. Given the request the agent made, anyone recomputes it and knows the receipt covers that request and nothing else.

mandate_hash: SHA-256 over a canonical string of the mandate’s terms:

terms-v4|mandate_id=…|version=…|agent_id=…|owner_id=…|currency=…|settlement_chain=…|status=…|per_tx_limit=…|daily_limit=…|monthly_limit=…|per_entity_limit=…|entity_key=…|relational_cap=…|expires_at=…|agent_may_read_limits=…|allowed_resources=…|entity_limits=…|salt=…

terms-v2 stops at agent_may_read_limits, terms-v3 adds allowed_resources, terms-v4 adds entity_limits (caps per counterparty). A missing value is written none, booleans true/false. The owner reveals the snapshot and the salt to whoever needs the terms (an insurer, an auditor); the verifier recomputes the string and compares. Every change to a mandate is a new version with a new salt, so a receipt pins the terms that were in force at that moment, not the terms as they are today.

policy_hash: SHA-256 over policy-v1|org_id=…|version=…|text_sha256=…|profile_sha256=…|salt=…, where text_sha256 is the hash of the organization’s policy text and profile_sha256 the hash of its canonical JSON profile (none when there is none). For policy_source: starter the public starter text alone opens the commitment.

Verify one

pip install regent-receipt-verify        # or: npm i -g @regent-protocol/receipt-verify
curl -s https://control-api.regentprotocol.org/v1/control/.well-known/jwks.json > jwks-2026-10.json
 
regent-verify @receipt.txt --jwks jwks-2026-10.json \
  --request request.json \                      # optional: the request, to check args_hash
  --mandate mandate-v4-reveal.json \            # optional: the owner's reveal, to open mandate_hash
  --policy policy-v3-reveal.json \              # optional: the organization's reveal, to open policy_hash
  --counterparty-jwks merchant-jwks.json        # optional: to re-verify an embedded confirmation

What a run proves, in order:

  1. Signature: the JWS verifies under a key in the JWKS whose kid matches the header. Regent signed exactly these claims.
  2. Kind: typ receipt+jwt and aud regent-receipt; a receipt is not an access token.
  3. Issuer and time: iss is regent-control; iat is in the past; exp not yet reached.
  4. Request binding (with --request): args_hash recomputed from the request equals the claim.
  5. Mandate reveal (with --mandate): the revealed snapshot and salt open mandate_hash, and the snapshot’s version equals mandate_version.
  6. Policy reveal (with --policy): the same for policy_hash.
  7. Confirmation (with --counterparty-jwks): the embedded confirmation verifies under the counterparty’s key, its hash equals confirmation_hash, and it names the same decision_id, status, amount and currency as the receipt.
  8. Settlement reference: settlement_ref and settlement_network are shown; with the chain’s own explorer or RPC you look the transaction up yourself.

The library exposes each step (verify_token, check_request_binding, check_mandate_reveal, check_policy_reveal, check_confirmation) so an integration can run only the ones it needs. regent-verify bundle runs the same checks over a whole evidence bundle: the retained receipt, the audit batch proof, Regent’s signed checkpoint and the epoch proof, and with --rpc the anchor transactions on the network (Audit Trail).

What is never in a receipt

  • A card number, CVV, expiry, bank account number or wallet private key. The rail holds the instrument; the receipt holds the rail’s reference to the settled money.
  • A shipping address, a person’s legal name, an e-mail address or a phone number. The person behind the agent is a responsible_party_id, bound at registration and resolved only by the organization.
  • Cart contents or line items. The receipt commits to the request (args_hash); it does not carry it.
  • The ceilings of the mandate or the text of the policy. Both are commitments; the owner reveals them to whom they choose.
  • Biometric data. A biometric step-up leaves approval_method: passkey+authid and nothing else.
  • The risk score. risk_model names the model version; the score and the signals stay with the organization.

Retention

A receipt is issued when a decision completes, filed into the organization’s audit trail and retained for ten years (exp). The audit trail is hashed, batched and anchored, so a receipt retained there also proves when it existed. An organization can read its receipts back at any time over the API and hand them, with the saved JWKS, to anyone who asks. A receipt in your own files verifies the same way; Regent does not need to be reachable, or to exist, for the check to pass.