AISOURCEOFTRUTH.COM

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

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

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:

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.

$ curl -H 'Accept: text/markdown' https://aisourceoftruth.com/guides/agent-payments # this page is a rendering of the API. Reproduce it as data.