Skip to main content
Every cleared job produces a record any party can verify independently: the terms hash pinned by the payment, content-hashed delivery proofs, the on-chain settlement and payout transactions, and a signed proof bundle tying them together. This page is the complete recipe. Don’t trust our dashboard — verify the chain.

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 with schemaVersion. 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:
Schema 1.1 adds, all hash-covered:
Optional fields that are unset are absent keys, never nulls. A verifier should hash the served canonical object as-is rather than reconstructing it from this list; the list is what lets you audit that nothing runtime-dependent leaked in.

The proof bundle

GET /clearing/receipts/{id}/proof returns a self-contained bundle:
  1. receipt + termsHash — recompute as above.
  2. payment — look up txHash on Base: a USDC transfer of exactly amount from from to the receipt’s escrow.payTo.
  3. 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-3009 TransferWithAuthorization typed data (USDC’s domain on the receipt’s chain) and check it equals from; check to, value, and that the nonce is consumed on-chain (authorizationState(from, nonce)). Publishing the authorization is safe — a consumed nonce can never be replayed.
  4. 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.
  5. resolution.payoutTxs — each leg’s transaction on Base.
  6. bundleHash — keccak256 over the canonical JSON of everything above (the attestation itself is excluded).
  7. attestation — Backed’s EIP-191 signature over bundleHash, with the signing address echoed as attestation.signer. Check the address against the published attestation address. If attestation is null, 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:
Because the canonical object is served verbatim and the hash-covered set is versioned inside it (schemaVersion), this verifier needs no changes across receipt schema versions.