x402 V2
Payments
Every paid tool uses the same handshake. Browsers that prefer text/html get the
paywall UI. Agents that prefer application/json get a JSON 402 body. Both include
the base64 PAYMENT-REQUIRED header.
Cursor, Claude Desktop, and VS Code spawn one local stdio process. Config and spending-key
payment: /docs/mcp. HTTP agents keep using @x402/fetch.
Parameters before payment
Unpaid requests return HTTP 402 even if query parameters or POST items are missing or invalid, so CDP and agents can index the path. After a PAYMENT-SIGNATURE, invalid params return HTTP 400 JSON before settlement. magent does not charge. Fix the params, then request a new 402 quote for that complete URL. Catalog misses (empty matches, found=false) are valid paid 200s.
Handshake
- GET the tool with Accept: application/json (do not send Accept: text/html unless you want the human paywall).
- HTTP 402 means you have not paid. Decode the base64 PAYMENT-REQUIRED header. HTTP 503 is not a new quote.
- Sign accepts[0] (exact, EIP-3009) with validBefore = now + maxTimeoutSeconds (600 seconds), or accepts[1] (batch-settlement deposit/voucher) on product GET. Ping and POST {items} stay exact. Magent retries transient facilitator 429/5xx before answering.
- Retry the same URL with PAYMENT-SIGNATURE (base64 JSON of accepted and payload). Magent attaches canonical extensions.bazaar on CDP verify/settle; echoing 402 bazaar is optional.
- Success is HTTP 200 JSON plus PAYMENT-RESPONSE. exact settles before the tool. batch-settlement verifies (and deposit-settles) before the tool and commits the charge after HTTP 2xx. HTTP 503: retry the same PAYMENT-SIGNATURE. Mint a new exact nonce only after a new HTTP 402.
Guarantees
- HTTP 402 is unpaid, including a missing query. After PAYMENT-SIGNATURE, invalid parameters return HTTP 400 before settlement. You are not charged. HTTP 402 never includes the tool JSON.
- exact: settlement finishes before the tool (paymentFlow upfront). batch-settlement: verify/deposit before the tool; chargedCumulativeAmount commits after HTTP 2xx. Uncertain or failed settlement fails closed (HTTP 503). Retry the same PAYMENT-SIGNATURE.
- HTTP 402 is unpaid only. Do not sign a second authorization because of a 503.
- Execution is timeout-bounded and concurrency-capped.
- Calculator inputs are stored encrypted for allowlisted operators (Magent Console). They are not in public logs, SSH lookups, catalog, or rollups. Request logs store path without query.
Schemes
magent accepts only the offered schemes. CDP may list others; sending them is HTTP 402. Same-path POST {items} is still scheme exact: one EIP-3009 authorization for GET unit plus $0.002 per extra item. That is not x402 batch-settlement (payment channels / vouchers).
| Scheme | Status | Meaning |
|---|---|---|
exact |
offered | Fixed-price USDC on Base. The buyer authorizes the advertised amount (EIP-3009). magent settles before the tool runs (paymentFlow upfront). |
batch-settlement |
offered | Payment-channel vouchers claimed later in batches. Exact stays accepts[0]. Same-path POST {items} is still exact. |
upto |
not offered | Not offered. Usage-based: buyer authorizes a ceiling, seller settles the actual amount after work. Reserved for a future metered tool. Not for current calculators or code search. |
Payment channels (batch-settlement)
Deposit USDC into the x402 channel contract, then sign cumulative vouchers. Exact remains accepts[0] for one-off EIP-3009.
accepts[0] is always exact. accepts[1] is batch-settlement on product GET only, and only while offered. Ping and POST {items} stay exact.
| Field | Value |
|---|---|
| Status | offered |
| CREATE2 | 0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003 |
| withdrawDelay | 86400 seconds |
- Not the same as POST {items} bulk (that is still exact).
- Product GET only. Ping, POST {items}, paywall.js, and canary stay exact.
- Verify (and deposit settle) before the tool. Charge commit after HTTP 2xx.
- Refund skips the tool. Full drain closes locally; a later deposit reopens the same channelId.
Headers
| Header | Role |
|---|---|
PAYMENT-REQUIRED |
Server challenge. Base64 JSON. Present on unpaid HTTP 402 only. HTTP 503 does not include a new quote. |
PAYMENT-SIGNATURE |
Client payment. Base64 JSON. Required to settle and run the tool. Reuse this header on HTTP 503. Sign a new one only after a new HTTP 402. |
PAYMENT-RESPONSE |
Settlement receipt on HTTP 200. |
Shared payment errors
Tool-specific 400 codes live on each tool page. Those codes return before settlement; you are
not charged. payment_required is listed once there after merge.
| HTTP | Code | When |
|---|---|---|
| 402 | payment_required |
Missing or invalid PAYMENT-SIGNATURE; decode the PAYMENT-REQUIRED header |
| 409 | payment_in_progress |
The same authorization nonce is already being settled; retry shortly |
| 429 | rate_limited |
Too many requests from this client |
| 503 | settlement_uncertain |
Settlement is unconfirmed; retry with the same PAYMENT-SIGNATURE |
| 503 | settle_failed |
Settlement failed; retry with the same PAYMENT-SIGNATURE shortly |
| 503 | facilitator_unavailable |
Payment facilitator unavailable |
| 503 | facilitator_misconfigured |
Payment facilitator is not configured |
| 503 | facilitator_unauthorized |
Payment facilitator rejected credentials |
| 503 | kyt_risk_detected |
Payment facilitator declined this request after compliance screening |
| 503 | request_blocked_by_location |
Payment facilitator blocked this request by location |
| 503 | opaque_403 |
Payment facilitator returned HTTP 403 without a JSON reason |
| 503 | ledger_unavailable |
Payment ledger unavailable |
| 503 | payment_unavailable |
Payment processing unavailable |