x402
x402 is a payment protocol for HTTP. The server sends the payment terms in a response header.
x402 lets a server ask for payment before it gives a resource. The server answers with HTTP status 402. The payment terms are in the PAYMENT-REQUIRED header.
Version 2 puts the challenge in a header. Version 1 put the challenge in the body. A version 2 client that reads a version 1 response finds an empty header. It cannot see the price, and it cannot give a good reason to stop.
What people use it for
An agent buys one API call
A research agent needs one search result. The API answers 402 and asks for 0.001 USDC. The agent pays and reads the result. It keeps no account and no API key.
A site sells one article
A reader opens an article behind a paywall. The server answers 402 and names the price. The reader pays for that article, and not for a month of them.
A tool bills each run
An agent calls a code-analysis tool. The tool charges 0.01 USDC for each run. The bill matches the work, so an idle agent pays nothing.
How a payment works
- 1The client asksThe client requests the resource. It sends no payment.
- 2The server refusesThe server answers 402. The PAYMENT-REQUIRED header holds the challenge as base64 JSON.
- 3The client paysThe client signs the payment. It sends the request again with a PAYMENT-SIGNATURE header.
- 4The server agreesThe server answers 200. The PAYMENT-RESPONSE header holds the result.
On the wire
- Status
- 402 Payment Required
- Challenge header
- PAYMENT-REQUIRED
- Credential header
- PAYMENT-SIGNATURE
- Receipt header
- PAYMENT-RESPONSE
- Challenge encoding
- base64 JSON
- Network format
- CAIP-2, such as eip155:84532
- Version field
- x402Version, a number, must be 2
- Facilitator
- Named by the challenge
What the challenge holds
The challenge is a JSON object. It has a version, a resource, and a list of payment options in the accepts array.
Each option in accepts names a scheme, a network, an amount, an asset, and a recipient. The amount is in atomic units, and it is a string. A number loses precision above 2 to the power of 53.
Where clients break
The version field causes the most trouble. Some servers send no version. Some send the version as a string. A client that assumes a version can read the wrong wire shape.
The network name causes the next most trouble. Version 2 uses CAIP-2 identifiers. A server that sends the old short name, such as base-sepolia, gives the client a chain it cannot match.
A challenge can also offer more than one payment option. A client that pays the first option, and not the cheapest one, pays too much.
x402 tests you can point a client at
21 ready-made x402 endpoints. Each one is a link. Testnets only, and nothing is stored.
- Compliant on Base Sepolia
A well-formed x402 v2 challenge. USDC on Base Sepolia.
Your client should Pay it.
- Compliant on Solana
A well-formed x402 v2 challenge. USDC on Solana devnet, paying a base58 address.
Your client should Pay it, or skip it if it is EVM-only.
- v1 network name
A v2 challenge naming the network base-sepolia instead of eip155:84532.
Your client should Refuse it.
- No version field
The challenge omits x402Version entirely.
Your client should Refuse it rather than assume a version.
- Undecodable header
The PAYMENT-REQUIRED header is not valid base64.
Your client should Fail cleanly, and not crash.
- No challenge header
A bare 402 with no PAYMENT-REQUIRED header at all.
Your client should Treat it as unpayable, and not hang.
- Mismatched payTo
The recipient is not the one the endpoint was configured with.
Your client should Notice who it is about to pay.
- Inflated amount
The amount is 1000x the price, still atomic-shaped.
Your client should Catch it against its own maximum, or the asset's decimals.
- Expensive request
A challenge asking $50, far above a sane per-call ceiling.
Your client should Refuse it before signing anything.
- Zero-value charge
A well-formed challenge asking for 0 USDC on Base Sepolia.
Your client should Refuse to sign a zero-value payment.
- Oversized challenge header
A challenge header padded to ~14KB on Base Sepolia, over the 8KB buffer many proxies enforce.
Your client should Fail cleanly; a reduced-limit HTTP parser rejects the response.
- Amount as a number
A challenge whose amount is a bare JSON number, not an atomic-units string.
Your client should Refuse it, or read the amount as a big-integer string.
- Multiple payment options
Two accepts entries on Base Sepolia, an inflated decoy before the real one.
Your client should Pay the cheaper option, not blindly the first.
- No window to pay
An x402 challenge offering maxTimeoutSeconds of 0, so there is no time in which the payment could land.
Your client should Refuse a challenge it cannot satisfy in time.
- Version as a string
An x402 challenge whose x402Version is the string "2" where the spec requires the number 2.
Your client should Refuse it rather than coerce the version and carry on.
- Signed offer and receipt (JWS)
A compliant x402 challenge carrying a JWS-signed offer, and a signed receipt on the paid retry. The key is named by kid and resolved from /.well-known/did.json.
Your client should Pay it, then verify the offer and the receipt against the published key.
- Signed offer and receipt (EIP-712)
A compliant x402 challenge carrying an EIP-712 signed offer, and a signed receipt on the paid retry. The payload travels beside the signature and the signer is recovered from it.
Your client should Pay it, then recover the signer and check it against the domain.
- Offer signature does not verify
A well-formed signed offer whose signature will not verify against the published key.
Your client should Refuse it. Checking the shape is not checking the signature.
- Offer that already expired
A genuinely signed offer whose validUntil is in the past. The signature is valid; the commitment is not.
Your client should Refuse it rather than trust a valid signature over a dead expiry.
- Offer contradicts the challenge
The signed offer commits to 1000x the amount its accepts entry advertises, while acceptIndex still points straight at that entry.
Your client should Refuse it. Match offers to accepts by the signed fields, not by acceptIndex.
- Receipt for somebody else's payment
The paid retry returns a genuinely signed receipt that names a different payer.
Your client should Pay it, then reject the receipt: a valid signature is not a receipt for your payment.
How this differs from MPP
Both protocols answer 402 and both settle on a blockchain. They differ in the headers they use, who verifies the payment, and whether they send a version at all.
Compare x402 and MPP