402 has been "reserved for future use" since HTTP/1.1. A protocol called x402 finally uses it: the server answers with a price, the client pays a tiny amount and retries. No account, no API key. Yes, the payment is a stablecoin (USDC). I know how this sub feels about crypto, so think of it as a payment rail and judge the HTTP part.
The flow, simplified (the headers are base64 JSON):
```
GET /weather?city=Oslo
← 402 Payment Required
PAYMENT-REQUIRED: { amount: "1000", asset: USDC, network: base, payTo: 0x… }
GET /weather?city=Oslo
PAYMENT-SIGNATURE: <signed payment authorization>
← 200 OK { ...data... }
PAYMENT-RESPONSE: { transaction: 0x… }
```
I run a free directory of these APIs, and its checker tries to actually buy from each one. Latest attempt per API: 58% delivered what they promised. The rest broke in ways that are worth knowing if you ever build one:
1. Paid, then got 402 again (288 APIs). The server asks for payment, receives a valid one, and asks again. Usually it couldn't verify or settle the payment, so it fell back to the challenge. When I checked a batch on chain, about 4 in 5 had never settled. If verification fails, return an error that says why. A second 402 tells the client nothing.
2. Paid, then got a 500 or nothing (289). Settle after you've produced the response, not before. If your handler can crash, the customer shouldn't be charged for the crash.
3. Paid, got data that didn't match what was advertised (126). If you publish an output schema, stick to it. Also: an HTML error page served with a 200 is still an error page.
4. Delivered data, but the payment never landed (47). The opposite bug: it served first, settlement failed silently, and it gave the data away free. Check the settle result.
5. The price in the 402 didn't match the listed price (103). A careful client refuses to pay a price it didn't expect, so changing it in one place quietly loses those sales.
6. Refused before any payment (765). Some of these are on my side: the endpoint needed query parameters my request didn't send. If your endpoint needs input, describe it in the 402 response. That's the only documentation a client is guaranteed to read.
Bonus gotcha: keep the PAYMENT-REQUIRED header small. Python's aiohttp rejects any header line over 8,190 bytes by default, so a big header with a full JSON schema inside makes the request fail before anyone reads the price.
The directory and its numbers are free to read, no account: https://nohumans.directory (method: /methodology, live totals: https://api.nohumans.directory/v1/stats). Happy to answer anything about the protocol side.