Verify before paying: ACP, UCP and x402
A buying agent checks the registry once, after it knows what it is buying and before it commits payment. One call covers up to 1000 digests and needs no token:
POST /v1/verify-batch {"digests": ["<digest>", ...]}
Where the call goes
- ACP (Agentic Commerce Protocol). The agent learns the items when it creates or updates the checkout session. Call verify-batch with the items' digests before it completes the session and hands over the payment token.
- UCP (Universal Commerce Protocol). Same rule: after the checkout lists the items, before the agent authorizes payment.
- x402 (HTTP 402). The server answers 402 with its payment requirements. Call verify-batch for the resource's digest before signing the payment payload and retrying the request with it.
- Any other rail. Check after the item is known and before money moves.
The seller can include the digest in its product data or response headers. The agent can also hash the delivered bytes itself and look the hash up as an asset at /a/{content_hash}.
What to do with the answer
present: false: no record exists. Treat the claim of provenance or verification as unsupported.sealed: true: the record was sealed under a legal or policy takedown. Its digest and position stay public, but do not transact on the content.errata_countabove zero: corrections were appended. Read them on the asset page before deciding.judge_version: the judge a verification was scored under. If that judge was recalled, its cohort is listed at/v1/judges/{hash}.log_inclusion.proof: an RFC 6962 audit path against a published daily root.pending: truemeans the record is newer than the latest root; the record still exists and is signed.
The check is free, anonymous and logs no reader identity, so an agent can check without revealing what it is about to buy.
Witness the mandate and the receipt
A receipt shows a payment went through. It does not show that a mandate existed before it. Record both by digest and the log order shows it later, in a dispute, without the registry holding anything but hashes.
1. When the mandate is signed, the buyer agent's publisher posts a mandate record: mandate_digest, protocol (ap2, acp, x402, ack-pay or other), mandate_type (AP2 intent, cart, checkout or payment, or the open forms open-checkout and open-payment), optional payer, payee and agent handles, issued_at and optional expires_at. Keep the record digest the answer returns.
2. When the payment settles, the merchant's publisher (or the same one) posts a settlement record: receipt_digest, protocol, settles (the mandate RECORD's digest) and settled_at.
Ingest refuses a settlement whose settles is not a mandate record already in the log (validation_error). So a settlement's log index is always greater than its mandate's. Both records are covered by a signed checkpoint within seconds.
How to hash
Hash the mandate or receipt the way its protocol signs it, and send only the digest:
- AP2. Mandates are SD-JWT credentials. Hash the exact bytes of the SD-JWT up to and including its last
~(no key binding JWT): the same input assd_hash, so the digest equals a payment receipt'sreferencedecoded from base64url. Receipts are JWTs: hash the compact form. - x402. The PaymentPayload and SettlementResponse travel as base64 JSON with no canonical form of their own. Decode the header and hash the RFC 8785 (JCS) form of the object, so either side can recompute it.
- ACK-Pay. Payment requests and receipts are signed JWTs: hash the compact form.
paymentDigest(value) in the SDK (payment_digest in Python) does this: a string or bytes hash as exact bytes, an object as JCS. buildMandate and buildSettlement (build_mandate, build_settlement) take the mandate or receipt itself, hash it on your machine, and never put it in the record.
What never goes in the record
Both profiles are hashes only. A card number, a wallet secret, an amount, a name, an email or a full payload is not a field, and ingest refuses it by name with a 422. Use per-merchant pseudonyms for party handles, never an account number. The registry never holds, moves or settles money.
Show the order later
The settlement's page at /r/{digest} links its mandate and shows both log positions and the first checkpoint that covers each, with the time it was signed. The mandate's page lists its settlements. To check offline, fetch both inclusion proofs at the same ?tree_size= and run verifyMandateOrder (SDK), verify_mandate_order (Python) or node verify.mjs --order mandate.json settlement.json --policy https://aisourceoftruth.com/log/policy. Both proofs must verify against one signed head and the mandate's leaf must come first. client.checkMandateOrder(settlementDigest) fetches everything and runs the check.
The records show what was recorded and when. They do not show that a mandate authorized a payment, and they are not a dispute ruling.