Getting your delivery receipt
A paid regime-signal call is intended to mint a signed EIP-712 delivery receipt, anchored on Base via EAS within a few hours. Your HTTP response does not contain it — and that is correct. Here is where it actually lives, how to derive its id yourself, and the cases where no receipt is minted at all.
Verified against a live minted receipt on 2026-09-01.
“My response said receipt: null — did something break?”
No. That is the expected response, and your receipt almost certainly exists.
x402 settles your payment after the endpoint has already returned your data. At the moment your response is assembled, the settlement transaction hash does not exist yet — and a receipt without its settlement transaction would be an unverifiable claim, so we refuse to mint one. Shortly after settlement completes, the gateway makes a second, authenticated call that mints the receipt out of band. That call is retried on failure; a receipt that never appears is one of the refusal cases below.
- You pay and receive your signal, with
receipt: null. - Settlement lands on Base.
- The receipt is minted, signed, and stored — bound to your actual payment.
Finding your receipt id
You are never sent the id, because you can compute it yourself from data you already hold. This is deliberate: the id is a hash of the receipt's contents, so deriving it and having it resolve is itself a check that the receipt describes exactly the delivery you experienced.
The receipt is a canonical JSON object with these keys in this exact order, addresses and hashes lowercased, issued_at as a decimal string. The block below shows shape and key order only — the values are illustrative placeholders, and it is pretty-printed, so it is not the byte string you hash. The bytes you hash have sorted keys and no insignificant whitespace (see below).
{
"issued_at": "1700000000",
"network": "eip155:8453",
"payer": "0x1111111111111111111111111111111111111111",
"payment_nonce": "0x2222...2222",
"request_hash": "0x3333...3333",
"resource": "regime-signal:BTC:4",
"response_hash": "0x4444...4444",
"settlement_tx": "0x5555...5555",
"vendor": "0x6666666666666666666666666666666666666666"
}You do not have to guess whether your serializer agrees with ours: /proof returns the exact string it hashed as canonical_json, so if a derivation disagrees you can diff yours against it directly.
Where each field comes from
| Field | Your source |
|---|---|
payer | your wallet address |
payment_nonce | the nonce in the EIP-3009 authorization you signed |
settlement_tx | the transaction field of the PAYMENT-RESPONSE header on your paid response |
resource | regime-signal:{ASSET}:{h} — uppercase asset, integer horizon, from your own request |
request_hash | canonical hash of the normalized request {asset, h} — asset uppercased, h an integer, and always under the key h even if you sent horizon_h. Hash {"asset":"BTC","h":4}, not your literal body. |
response_hash | canonical hash of the signal object you received |
issued_at | the issued_at field inside that same signal object |
network | eip155:8453 (Base) |
vendor | our published receipt-signer address |
The id is then:
id = keccak256( 0x00 || canonical_json_bytes )
The 0x00 prefix is a domain separator distinguishing leaves from internal nodes in the Merkle tree the receipt is later anchored in. canonical_json uses sorted keys and no insignificant whitespace; /proof returns the exact string it hashed as canonical_json, so you can diff yours against ours if a derivation disagrees.
Then fetch:
curl https://x402.payperbyte.io/proof/{id}That endpoint is free and unauthenticated — a receipt lookup never costs anything.
What /proof gives you, and how to check it
receipt— the stored record, with the EIP-712 signature nested atreceipt.signature(not a top-level field), under domain{name: "BYTE Delivery Receipt", version: "1", chainId: 8453}. Recover the signer and confirm it matches the receipt-signer address published below. Note this object also carriesid,hour_bucketandcreated_atand uses checksummed addresses — hashcanonical_json, never this object.canonical_json— the exact bytes hashed into the id.merkle—recomputed_root, your leaf'sproofandleaf_index, andinternally_consistent. Replay the proof yourself; do not take our word for the root.anchor— where that root stands on-chain.
Anchor states
status | Meaning |
|---|---|
not_yet_anchored | Receipt exists and is signed; its hour has not been anchored yet. |
pending_anchor | The root for that hour is computed and stored, but no confirmed on-chain attestation yet. |
anchored | A confirmed EAS attestation exists on Base; eas_uid is non-null. |
root_mismatch | The recomputed root disagrees with the stored one. Treat this as a data-integrity failure and tell us. |
Anchoring runs hourly and deliberately lags the receipt's hour by about three hours, because a signal remains servable for up to two hours and late receipts must not be excluded from their own hour's root. A freshly minted receipt reading not_yet_anchored is normal. Check again later the same day.
To verify the anchor independently, call getAttestation(eas_uid) on the EAS contract at 0x4200000000000000000000000000000000000021 on Base and confirm the attestation's data contains the same Merkle root, the schema matches the published receipt-anchor schema, the attester is the vendor key, and it has not been revoked.
Published values to verify against
These are the reference values the checks above depend on. Both are on-chain facts you can confirm yourself rather than take from this page:
| What | Value |
|---|---|
| receipt-signer / vendor (also the attester) | 0xdb95aac32da62176c927da7a58e86d8d0033b8b5 |
| receipt-anchor EAS schema uid | 0xebe4c88bc76c9f6cf4fdad86b48d025182c436929643babff33d774bf4bf2ca9 |
| EAS contract (Base mainnet) | 0x4200000000000000000000000000000000000021 |
To confirm them independently, call getAttestation(uid) on the EAS contract with the eas_uid from your /proof response and check that the returned schema and attester match the two values above, and that revocationTime is 0:
export EAS_UID=0x... # the eas_uid from your /proof response cast call 0x4200000000000000000000000000000000000021 \ "getAttestation(bytes32)((bytes32,bytes32,uint64,uint64,uint64,bytes32,address,address,bool,bytes))" \ $EAS_UID --rpc-url https://mainnet.base.org
The returned tuple is (uid, schema, time, expirationTime, revocationTime, refUID, recipient, attester, revocable, data) — so the second field is the schema uid, the fifth is revocationTime, and the eighth is the attester. cast needs the output types spelled out or it cannot decode the struct.
Cases where no receipt is minted
These are the common cases, carried in the receipt_reason field. Each is deliberate and fails closed rather than issuing a receipt we cannot stand behind:
| Reason | What happened |
|---|---|
settlement pending | Settlement had not produced a transaction hash. |
response changed since delivery | The signal changed between your delivery and the mint attempt, so a receipt would have attested bytes you never received. We refuse rather than attest the wrong thing. |
payment_nonce already used | A receipt was already minted for that payment. One payment, one receipt, permanently. |
no verified payment context | The mint request did not carry a valid gateway-signed context — only the gateway can authorize a mint. |
What a receipt does and does not prove
It proves which bytes were delivered, to which payer, against which settled payment, signed by the vendor and anchored so that later alteration is detectable. It is evidence of authenticity and tamper-evidence.
It is not a claim that the signal is correct. Whether a regime call turns out to be right is a separate, public question: the scoring rule is deterministic and recomputable from public Chainlink rounds, and lives at x402.payperbyte.io/methodology and x402.payperbyte.io/track-record.
If something looks wrong
Email hello@payperbyte.io with the settlement transaction hash and the id you derived. A root_mismatch, a signature that recovers to an unexpected address, or a derivation that disagrees with our canonical_json are all things we want to hear about.