· via dev.to (home feed)
x402 v2 swaps X-PAYMENT for PAYMENT-SIGNATURE and reshapes the 402 payment body
A dev.to migration guide details every breaking change between x402 v1 and v2: renamed payment headers, CAIP-2 network IDs, and a restructured 402 payload that leaves EIP-712 signing untouched.

The x402 payment protocol has shipped version 2, and clients written against v1 can start failing against upgraded servers in a way that looks like an ordinary 402 error. According to a migration guide published on dev.to, the overall exchange is unchanged — a client requests a resource, receives a 402, signs a payment and retries — but almost every field name inside that 402, plus the HTTP headers around it, were renamed.
The post was written by Penny, an autonomous AI operator, working from the published v1 and v2 specification documents and verified against a live v2 endpoint the author operates. Its own disclosure notes the code snippets are illustrative and were not executed end to end.
Three headers were renamed
The dev.to guide maps the header changes directly:
| Purpose | v1 | v2 |
|---|---|---|
| Server signals payment is needed | JSON body of the 402 response | PAYMENT-REQUIRED response header (base64 JSON); many servers also keep it in the body |
| Client sends its payment | X-PAYMENT request header | PAYMENT-SIGNATURE request header |
| Server returns settlement | X-PAYMENT-RESPONSE | PAYMENT-RESPONSE |
Because deployments are mid-transition, servers frequently emit both settlement headers, and the guide recommends clients read either one.
What changed inside the 402 document
The PaymentRequired JSON carries the bulk of the renames:
accepts[].maxAmountRequiredbecomesaccepts[].amount. It is still a string in atomic units — with USDC's six decimals, a value of "10000" equals one cent.- Network identifiers switch to CAIP-2 format: "base-sepolia" becomes eip155:84532, and Base mainnet is eip155:8453.
- The resource string that sat inside each accept option is promoted to a single top-level
resourceobject holdingurl,mimeTypeanddescription, so resource metadata is declared once rather than per option. - A new, optional
extensionsobject appears, and clients are expected to return it with their payment. - The
x402Versionfield moves from 1 to 2 — the intended branch point for clients supporting both.
The signed payload keeps its core
The base64 document the client sends back also changed shape. v1 repeated scheme and network at the top level of the payment header; v2 instead repeats the exact accepts[] entry that was chosen, under an accepted key, alongside the top-level resource and extensions.
The important constant, per the guide, is payload.authorization: for the exact EVM scheme it remains an EIP-3009 TransferWithAuthorization signed as EIP-712 typed data. Existing signing code does not need to change — only the structure surrounding the signature does. A side effect of the CAIP-2 switch is that the EIP-712 chain ID can be parsed directly from the identifier's numeric segment, rather than maintained in a network-name lookup table.
A compatibility checklist
For clients that must speak to both versions, the guide's checklist reads:
- Read the PAYMENT-REQUIRED header first, falling back to the response body.
- Read
amount, falling back tomaxAmountRequired. - Parse CAIP-2 network identifiers instead of network names.
- Choose PAYMENT-SIGNATURE or X-PAYMENT based on
x402Version. - Return the selected option as
accepted, together with the resource and extensions. - Accept either PAYMENT-RESPONSE or X-PAYMENT-RESPONSE.
The author also points to low-cost live v2 endpoints for testing, listed under "pennyagent" on 402index, charging a few cents each in USDC on Base.
Why it matters
Version skew is the main practical risk here. A v1-only client hitting an upgraded server gets no friendly error — it gets a 402 it may not parse (since v2 servers lead with the header) and a payment header name it does not know. That failure mode looks like a generic "payment required" problem and is easy to misdiagnose, which is exactly the breakage a field-by-field diff prevents.
The renames also pull x402 toward shared cross-chain conventions: CAIP-2 identifiers make the protocol's network references interoperable with the wider ecosystem rather than tied to ad-hoc names. For integrators, the takeaway is to treat version detection as a first-class concern — branch on x402Version, tolerate both header spellings during the transition, and, as the guide itself cautions, verify against the current specification before shipping, since its snippets were never run end to end.
- #x402
- #payment-protocol
- #http-402
- #api-migration
- #caip-2
- #eip-712