x402 v2 buyer flow explained: who signs and who settles
x402 turns 402 Payment Required into a working payment step: a paid API answers with a price, the client signs a stablecoin payment and retries, and the seller settles it and serves the response. This guide follows one payment from the buyer's side, in x402 v2 with the exact scheme and USDC on Base. The short version: the buyer signs, the seller settles. A buyer that settles its own payment is the most common mistake, and the end of this guide explains why.
The four parties
| Party | Role |
|---|---|
| Buyer | The client that wants the resource. For an AI agent, the code that makes the HTTP request. |
| Wallet | Holds the USDC and signs a transfer authorization. It can be a CDP wallet or a key on the buyer's machine. |
| Seller | The paid API. It sets the price and decides when to serve. |
| Facilitator | A service the seller uses to verify the signed payment and submit it on-chain. |
A spending control plane like Burnbound adds one step on the buyer's side: before the wallet signs, it checks the payment against the agent's rules. It is not a party to the payment itself. It never holds funds and never talks to the facilitator.
Step 1: The first request gets a 402
The buyer sends an ordinary request:
GET /v1/report HTTP/1.1
Host: api.example.com
The seller answers 402 Payment Required with a PAYMENT-REQUIRED header. Its value is base64-encoded JSON that lists what the seller accepts:
{
"x402Version": 2,
"resource": { "url": "https://api.example.com/v1/report" },
"accepts": [
{
"scheme": "exact",
"network": "eip155:8453",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "10000",
"payTo": "0x…",
"maxTimeoutSeconds": 60
}
]
}
amount is in the asset's smallest unit. USDC has 6 decimals, so 10000 is 0.01 USDC. network is a CAIP-2 id: eip155:8453 is Base and eip155:84532 is Base Sepolia. A seller can list several entries, for example Base and Solana. The buyer picks one it can pay.
In x402 v1 the same information came in the response body, and the headers were X-PAYMENT and X-PAYMENT-RESPONSE. v2 moved it to the PAYMENT-* headers.
Step 2: The buyer decides whether to pay
This is the step x402 leaves to the buyer, and where an agent needs rules. Before signing, check at least:
- The host. Is this a seller the agent is allowed to pay?
- The resource. Does
resource.urlpoint at the host that answered? A challenge that names another host is a red flag. - The amount against a per-payment maximum and what is left of a daily budget.
- The network and asset. Only pay where the wallet holds funds and where you meant to pay.
With Burnbound, the MCP server sends the challenge and the URL to the Burnbound API, which evaluates the agent's policy and answers allow, deny or step-up (a human must approve). A denied payment is never signed. An allowed one is recorded and counts against the daily cap from that moment. See How to limit an AI agent's spending.
Step 3: The wallet signs an EIP-3009 authorization
For USDC, the exact scheme uses EIP-3009 TransferWithAuthorization: an EIP-712 signature that lets someone else move a fixed amount from the wallet to payTo, once, within a time window. The signed authorization has these fields:
| Field | Value |
|---|---|
from |
The buyer's wallet. |
to |
The seller's payTo. |
value |
The amount from the challenge. |
validAfter |
When the authorization starts to be valid (Unix seconds). |
validBefore |
When it stops being valid. Keep it short. |
nonce |
32 bytes. The USDC contract accepts each nonce from a wallet only once. |
Burnbound derives the nonce from the payment's id, so the same purchase always produces the same nonce and can move money at most once, even if it is signed again by mistake. The wallet needs no ETH: the signature is not a transaction.
Step 4: The buyer retries with PAYMENT-SIGNATURE
The buyer repeats the same request once, with the signed payload in a PAYMENT-SIGNATURE header (base64-encoded JSON):
{
"x402Version": 2,
"resource": { "url": "https://api.example.com/v1/report" },
"accepted": {
"scheme": "exact",
"network": "eip155:8453",
"amount": "10000",
"…": "…"
},
"payload": {
"signature": "0x…",
"authorization": {
"from": "0x…",
"to": "0x…",
"value": "10000",
"validAfter": "…",
"validBefore": "…",
"nonce": "0x…"
}
}
}
accepted is the seller's own entry, unchanged. Two rules keep this retry safe:
- Send it to the URL that asked for it. Do not follow a redirect with a signed payment attached.
fetch_paidnever follows redirects after paying. - Send it once. If the answer is lost, do not sign a new payment. With Burnbound, a retry with the same idempotency key replays the same purchase and never charges twice.
Step 5: The seller settles and serves
The seller passes the payload to its facilitator, which checks the signature, the amount, the payee and the time window, and submits the transfer to the USDC contract. The facilitator pays the gas. The seller then answers 200 with the resource and a PAYMENT-RESPONSE header that says whether settlement succeeded, with the transaction hash.
When exactly the seller settles, before or after running its handler, depends on its middleware. Either way, it is the seller's facilitator that submits the transfer.
Step 6: The buyer records the receipt
The buyer keeps the PAYMENT-RESPONSE as a receipt. The Burnbound MCP server reports it to Burnbound, which checks the transfer on-chain before it marks the payment settled. If the seller answers the paid request with something other than a 2xx, the result is an error (payment_rejected_by_seller or payment_not_completed), never paid, and the failed receipt stays in the audit log.
Why the buyer must never settle
The facilitator's /settle endpoint is for the seller. A buyer, or a tool acting for it, that submits its own authorization breaks the flow:
- You pay without being served. Settlement moves the USDC whether or not the seller ever answers. The seller has not accepted anything yet.
- The seller then refuses you. When the seller tries to settle the same authorization, the nonce is already used, so its facilitator rejects it. You get an error or another 402 instead of the resource.
- You pick a facilitator the seller did not choose. The seller trusts its own facilitator's verification, not yours.
So a buyer signs and sends; it never calls /verify or /settle. Burnbound follows this: neither your agent nor Burnbound calls a facilitator. See Concepts for the same flow in Burnbound's terms.
Try the flow without writing a client
The Burnbound MCP server runs this whole buyer flow inside one tool, fetch_paid, with the checks above built in. To see it against real sellers, pick one from the x402 API catalog, such as Exa or CoinGecko, and follow How to pay an x402 API from Claude Code. To set it up from scratch, start with the Quickstart.