The terms hash
termsHash = keccak256(canonical JSON of the hash-covered receipt fields)
Canonicalization follows RFC 8785 (JCS) restricted to the types the
receipt actually uses: strings, booleans, null, safe integers, arrays,
objects. Object keys sort by UTF-16 code units; amounts are fixed
6-decimal strings; timestamps are ISO-8601 UTC with milliseconds; floats
never appear. GET /clearing/receipts/{id} serves the exact canonical
object under receipt — recompute over it and compare with the published
termsHash.
Hash-covered fields, by schema version
The hash-covered set is versioned withschemaVersion. Runtime
fields — everything about the buyer, states, and post-offer timestamps —
are excluded by construction: the canonical object simply does not
contain them. In particular the canonical form has no buyer key at
all (not a buyer object with null fields).
Schema 1.0:
1.1 adds, all hash-covered:
The proof bundle
GET /clearing/receipts/{id}/proof returns a self-contained bundle:
receipt+termsHash— recompute as above.payment— look uptxHashon Base: a USDC transfer of exactlyamountfromfromto the receipt’sescrow.payTo.payment.authorization— present when Backed settled the payment as the x402 facilitator (null for direct transfers observed by the watcher). Verify it independently: recover the signer of the EIP-3009TransferWithAuthorizationtyped data (USDC’s domain on the receipt’s chain) and check it equalsfrom; checkto,value, and that the nonce is consumed on-chain (authorizationState(from, nonce)). Publishing the authorization is safe — a consumed nonce can never be replayed.deliveries— for hash proofs, hash the delivered content and compare; for url proofs, the recorded snapshot status and content hash are Backed’s witness record of what the URL served at post time.resolution.payoutTxs— each leg’s transaction on Base.bundleHash— keccak256 over the canonical JSON of everything above (the attestation itself is excluded).attestation— Backed’s EIP-191 signature overbundleHash, with the signing address echoed asattestation.signer. Check the address against the published attestation address. Ifattestationisnull, the bundle is served unsigned (the attestation key was not configured); treat it as unattested data and rely on the on-chain checks above, which need no signature from us.
Reference verifier
An independent reimplementation (shares no code with our backend) lives in the public tooling; the same ~40 lines work anywhere:schemaVersion), this verifier needs no changes
across receipt schema versions.