On this page
The x402 V2 core specification dates protocol version 2 to December 9, 2025. The payment still happens in one HTTP round trip: the server answers 402 with its terms, the client signs and retries, a facilitator verifies and settles. What changed is where each message travels and what its fields are called, so a V1 client and a V2 server do not understand each other. If the flow itself is new to you, read What is x402? first.
What changed on the wire
| Aspect | V1 | V2 |
|---|---|---|
| Payment terms | JSON body of the 402 response | PAYMENT-REQUIRED header, Base64 JSON |
| Client payment header | X-PAYMENT | PAYMENT-SIGNATURE |
| Settlement header | X-PAYMENT-RESPONSE | PAYMENT-RESPONSE |
| Network identifiers | Names such as base-sepolia | CAIP-2, such as eip155:84532 |
| Amount field | maxAmountRequired | amount |
| Resource description | resource URL inside each requirement | One top-level resource object |
| Chosen option in the payload | Scheme and network only | The full requirement, in accepted |
| Extensions | extensions object |
Beyond the headers
| Area | V1 | V2 |
|---|---|---|
error in the 402 terms | Required | Optional |
| Resource metadata | Description required, MIME type and output schema optional, in each requirement | One ResourceInfo object: URL required; description, MIME type, service name, tags and icon optional |
Reserved extra keys | None | assetTransferMethod and paymentFlow |
Facilitator GET /supported | kinds only | kinds, extensions and signers, all required |
SettleResponse | payer required | payer optional, amount and extensions added |
The error codes changed too. The V1 code for a wrong amount, invalid_exact_evm_payload_authorization_value, meant "amount insufficient"; V2 replaces it with invalid_exact_evm_payload_authorization_value_mismatch, "amount not an exact match". V2 also adds settlement_pending, the only code the specification marks non-terminal. The full list, with fixes, is in the x402 error codes reference.
The same offer in V1 and V2
Both examples come from the HTTP transport specifications and describe the same payment: 10000 atomic units of the token at 0x036C…CF7e on Base Sepolia, to 0x2096…287C, within 60 seconds. In V1 the client reads it from the response body:
{
"x402Version": 1,
"error": "Payment required to access this resource",
"accepts": [
{
"scheme": "exact",
"network": "base-sepolia",
"maxAmountRequired": "10000",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
"resource": "https://api.example.com/premium-data",
"description": "Access to premium market data",
"mimeType": "application/json",
"outputSchema": null,
"maxTimeoutSeconds": 60,
"extra": {
"name": "USDC",
"version": "2"
}
}
]
}
In V2 the body is left to the server, and the client Base64-decodes the PAYMENT-REQUIRED header instead:
{
"x402Version": 2,
"error": "PAYMENT-SIGNATURE header is required",
"resource": {
"url": "https://api.example.com/premium-data",
"description": "Access to premium market data",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "eip155:84532",
"amount": "10000",
"asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
"payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
"maxTimeoutSeconds": 60,
"extra": {
"name": "USDC",
"version": "2"
}
}
]
}
Every field is explained on the x402 V2 headers page.
Migration steps for resource servers
- Send the terms in the PAYMENT-REQUIRED header. Answer 402 with a Base64-encoded
PaymentRequiredobject,x402Version2, inPAYMENT-REQUIRED. The V2 transport treats the response body as a server implementation concern, so clients must not need it. - Move the resource out of each requirement. Replace the per-requirement
resource,descriptionandmimeTypewith one top-levelresourceobject, and set itsurlto the exact URL the client requested. - Rename the amount and convert the networks.
maxAmountRequiredbecomesamount, still an integer string in atomic units. Network names become CAIP-2 identifiers (table below). - Read PAYMENT-SIGNATURE instead of X-PAYMENT. The payload now carries the chosen requirement in
accepted. Match it against your ownacceptsentries and send your own requirement, withx402Version2, to/verifyand/settle. - Return PAYMENT-RESPONSE instead of X-PAYMENT-RESPONSE. HTTP 200 with the settlement result on success, HTTP 402 with
success: falsewhen settlement fails. - Declare and enforce the payment flow. When an option settles before the handler runs (
upfrontorescrow), V2 requiresextra.paymentFlowin it. Servers must reject transfer method and payment flow combinations they do not support.
| V1 name | V2 (CAIP-2) | Network |
|---|---|---|
base-sepolia | eip155:84532 | Base Sepolia |
base | eip155:8453 | Base mainnet |
avalanche-fuji | eip155:43113 | Avalanche Fuji |
avalanche | eip155:43114 | Avalanche mainnet |
Migration steps for clients and agents
- Read the header, not the body. Match
PAYMENT-REQUIREDcase-insensitively, Base64-decode it and parse the JSON. - Check the binding.
resource.urlshould equal the URL you requested. - Echo the whole requirement. Put the chosen
acceptsentry inaccepted, the signed data inpayload, and send it inPAYMENT-SIGNATURE. Echo anyextensionsyou received: you may add information but not remove it. - Skip what you do not recognize. Clients must not build a payment for a
paymentFlowthey do not recognize, and should preferauthorizationwhen a resource also offersupfrontorescrow. - Update your spending policy. Allowlists keyed on V1 network names must switch to CAIP-2, and amount caps now compare against
amount. The agent spending policy guide covers the full set of limits. - Read the outcome from PAYMENT-RESPONSE. Treat
settlement_pendingas unresolved: reconcile on chain with the returned hash before paying again.
Migration steps for facilitators
- List V2 kinds in
GET /supported:x402Version2 with CAIP-2 networks. A facilitator can list V1 and V2 kinds side by side, since each kind carries its ownx402Version. - Add the now-required
extensionsarray andsignersmap, which pairs CAIP-2 patterns such aseip155:*with your public signer addresses. - Keep
/verifyread-only: the V2 specification states it must not commit payment state or write on chain. - Return
settlement_pending, with a non-emptytransactionandnetwork, when a broadcast transaction cannot be confirmed in time. The facilitator security guide explains why.
Verify the migration
Settlens tests x402 V2 only, which makes it a direct way to confirm a migration from the outside. A passive scan sends no payment. Against an endpoint that still answers the V1 way, with the terms in the body, the header check fails. The bundled demo's /missing-header route answers 402 without the header, and a V1 server gives the same result:
settlens scan http://127.0.0.1:4402/missing-header --no-write
Settlens x402 assessment fa65d786
Targets 1 · Active 0 · Settlement calls 0
127.0.0.1 GET http://127.0.0.1:4402/missing-header
4 pass · 1 fail · 0 warn · 1 skip
FAIL high PAYMENT-REQUIRED header is present
The response does not include PAYMENT-REQUIRED.
SKIP medium Payment requirements remain stable
Only one successful sample was available.
Total: 4 pass · 1 fail · 0 warn · 1 skip
Once the server sends a valid V2 header, every passive check passes:
settlens scan http://127.0.0.1:4402/secure --no-write
Settlens x402 assessment 11984f96
Targets 1 · Active 0 · Settlement calls 0
127.0.0.1 GET http://127.0.0.1:4402/secure
13 pass · 0 fail · 0 warn · 0 skip
Total: 13 pass · 0 fail · 0 warn · 0 skip
Two more signals help during the transition:
- A V1 object Base64-encoded into a V2 header is rejected too. Passed to the MCP tool
evaluate_payment_requirementswhen this page was built, the V1 example above got the decisiondo_not_pay, withschema.payment_required,policy.networkandpolicy.acceptable_optionfailing. - A facilitator scan (
settlens facilitator) failsfacilitator.supported_schemawhile/supportedstill has the V1 shape, withoutextensionsandsigners, andfacilitator.v2_capabilitywhen it lists nox402Version2 kind.
To check one header by hand, paste it into the x402 payment request checker.
To gate every deploy on these checks, see CI gating; the check reference lists each check with its fix.
Compatibility during the transition
The official @x402/core schemas parse both versions, keyed on x402Version, but the two wire formats do not mix: a V1 client looks for the terms in a response body that V2 leaves to the server, and a V2 client finds no PAYMENT-REQUIRED header on a V1 response. Facilitators differ in which versions they still accept, and /supported is where each one says so, kind by kind. The specifications set no end-of-life date for V1; this page does not guess one.
Frequently asked questions
Is x402 V2 backward compatible with V1?
Not on the wire. V2 moves the payment terms into the PAYMENT-REQUIRED header and renames the client and settlement headers, so each side must speak the same version. A server or facilitator can support both by branching on x402Version.
What replaces maxAmountRequired in x402 V2?
The amount field. It is still an integer string in the asset's atomic units. For the exact scheme it is the exact amount to pay; for the upto scheme it is the maximum authorized at verification time.
Does Settlens test x402 V1 endpoints?
No. Settlens checks x402 V2 only. A V1 endpoint fails the PAYMENT-REQUIRED header check, which is how a scan confirms that a migration has not shipped yet.