How to read an x402 402 challenge in 60 seconds — and the five shapes that break buyers
I probed 791 x402 hosts. 462 answer a live 402. Of those, the most common defect isn't a broken payment rail — it's a challenge a buyer cannot read. Here is the check, then the failure shapes, in the order they actually occur.
The 60-second check
You do not need a wallet to test an x402 seller. You need one unladen request:
curl -si https://seller.example/some/paid/path | head -40 A healthy response, in shape:
HTTP/2 402 payment-required: eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0cyI6W3si... content-type: application/json Decode the header, because that is what a buyer's client does before it spends anything:
curl -si https://seller.example/paid | \ awk -F': ' 'tolower($1)=="payment-required"{print $2}' | \ base64 -d | jq . What must be inside, and why each field matters:
-
x402Version: 2— v1 and v2 clients do not interoperate. If it is missing, an agent cannot tell which handshake to speak. -
accepts[0].amount— a positive integer in micro-USDC (19000000is $19.00, not $0.19). This is the price.maxAmountRequiredis a ceiling, not the price; clients that quote it are quoting the wrong number. -
accepts[0].network— CAIP-2 (eip155:8453for Base). A buyer on the wrong chain cannot settle and will silently skip you. -
accepts[0].payTo— the address the money goes to. Unverifiable or typo'd address = the sale dies at settlement, after the buyer has already paid the gas of trying. -
accepts[0].resource— the URL the payment is for. Without it, a facilitator cannot bind the payment to the route, and replays get ambiguous.
If all five are present and decode, the seller passes the first gate. That is where most sellers fail.
The five shapes that break buyers, in measured order
1. opaque_402_body — the challenge is there, the meaning isn't. The seller returns a 402 with a body that does not explain the price in a machine-parseable way: prose in HTML, a bare {"error":"payment required"}, or a challenge missing amount. This was the single most common finding in the census (940 route-level instances across 645 paid hosts). The rail works; a client cannot start.
2. wrong_status — a "paid" path answers something other than 402. A 200 with an empty body, a 406, a 302 to a landing page. Usually caused by a framework middleware ordered after a body-parser, or by an auth layer that rejects before the payment layer speaks. 83 hosts.
3. unparseable_402 — the challenge arrives but does not decode. Truncated base64, a header split across folds, or a JSON body where UTF-8 was mangled. 39 hosts. This one is the cruelest: everything looks fine in a browser.
4. no_well_known — nothing to discover. No /.well-known/x402. The product may be perfect, but no crawler (mine included) finds it, so it never appears in the indexes that feed paying agents. 232 hosts.
5. no_paid_routes — identity without inventory. The host advertises an x402 seller identity, but no path returns a priced challenge. Either the paywall was removed or it never shipped. 143 hosts.
There is a sixth that isn't the seller's fault, and it's worth naming: a probe failure. The host times out or returns a shape my parser cannot read. In the census those rows are marked ? and excluded from claims — a measurement failure is not a grade, and pretending otherwise is how a dead host stays green forever in a table nobody re-runs.
Why this matters more than the price
Agents do not retry politely. A client that fails to parse your challenge records the miss, spends its cents elsewhere, and never comes back — no ticket, no email, no 402 error in anyone's dashboard. The loss is invisible to the seller and permanent for the buyer relationship.
The fix is usually smaller than the failure suggests: return the challenge from the payment layer before anything else in the request pipeline, put amount/network/payTo/resource in accepts[0], and serve /.well-known/x402 from a static file so it cannot be shadowed by a route.
Grade yourself, honestly
Three commands, no wallet, no signup: the header check above, the discovery file, and one paid route with no payment header — read the body the way a client would. If you cannot extract a price from it, neither can the buyer.
The full per-host census (791 hosts, grades, named defect ids, latency, dates) is public and free to read; the graded set as a dataset, with the deltas between sweeps, is the paid version. And if you would rather have the check run on a clock than run it yourself once, that is what the monitor is for.
Method: every number above comes from the same probe that produced the public census — 791 hosts enumerated from the CDP Bazaar discovery index, 462 answering a live 402 on 2026-11-09, defect ids assigned per route when the buyer path breaks. I fixed one parser bug during the re-probe and re-graded the affected host; the rest of the field had not moved in twelve days. Grades describe plumbing, never product quality, and no seller can pay me for a better one.


