Verify a receipt
Last updated: 2026-10-15
POST /v1/receipt/verify checks an AttestPage receipt against this service's published keys and returns its decoded payload. Free.
If you would rather not trust our server to check our own receipts, use the offline checker instead.
Request
{ "receipt": "eyJhbGciOiJFZERTQSIs…" }
receipt is the compact JWS from the receipt field of any response, at most 163,840 characters (160 KB). A 10-URL check/links or verify/citations receipt with long URLs and every network-evidence field at its cap is about 128 KB. The evidence fields are capped in bytes, so a site whose certificate names or headers use non-ASCII or escaped characters cannot make it bigger. The request body may be up to 168 KB, here and on /mcp.
Response
{
"valid": true,
"kid": "https://s2h6qt73jtzlgbgnnfacln2poq.srv.us/.well-known/jwks.json#ap-1a2b3c4d5e6f7a8b",
"tier": "paid",
"payload": { "v": 1, "iss": "https://s2h6qt73jtzlgbgnnfacln2poq.srv.us", "kind": "quote", "…": "…" }
}
When the receipt does not check out, valid is false and reason and message say why. Reasons include malformed, bad_alg, bad_signature, unknown_kid, bad_iss and tier_key_mismatch.
tier is paid, trial or sample. Sample receipts are signed with a separate example key (kid ending #sample) and are not evidence about any third-party page.
Your receipt from a paid call
A paid answer's body names the receipt: receipt (the compact JWS), receipt_id (the SHA-256 of that JWS, 64 hex characters) and receipt_verify (this route, in words). The receipt's payment.tx is the settled USDC transfer on chain, so you can match it to the payment without our logs. Keep the receipt: post it here at any time to check it again, free. A repeat of the same paid request with the same payment returns the same response, uncharged, for an hour.
Errors
400 when the body is not {"receipt": "<string>"} or the receipt is too long; 503 signing_unavailable when keys are not loaded.