---
title: "x402 V1 to V2 migration: what changed on the wire | Settlens"
description: "Migrate an x402 integration from V1 to V2: the new PAYMENT-REQUIRED, PAYMENT-SIGNATURE and PAYMENT-RESPONSE headers, CAIP-2 networks, amount and steps."
url: https://settlens.com/learn/x402-v1-to-v2-migration
last_updated: 2026-10-13
published: 2026-10-13
---

# Migrating from x402 V1 to V2

> **In short:** x402 V2 moves the payment terms from the 402 response body into a Base64 PAYMENT-REQUIRED header, renames X-PAYMENT to PAYMENT-SIGNATURE and X-PAYMENT-RESPONSE to PAYMENT-RESPONSE, replaces maxAmountRequired with amount and identifies networks in CAIP-2 form, such as eip155:84532.

x402 V2 keeps the same handshake but changes almost every name on the wire. This guide lists the differences from the specifications, then the steps for resource servers, clients and facilitators, and how to confirm an endpoint really speaks V2.

The [x402 V2 core specification](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md) 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?](https://settlens.com/learn/what-is-x402) first.

> **Checked on Oct 13, 2026**
>
> The differences below come from the [V1](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v1.md) and [V2](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md) core specifications and their HTTP transports in the x402-foundation/x402 repository. SDK and facilitator support for V1 changes faster than the specifications: check your vendor's documentation for dates.

## What changed on the wire

_Wire-level differences between x402 V1 and V2 (HTTP transport)_

| 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 | No | `extensions` object |

### Beyond the headers

_Other differences between the V1 and V2 core specifications_

| 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](https://settlens.com/learn/x402-error-codes).

## 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:

**V1: body of the 402 response**

```json
{
  "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:

**V2: PAYMENT-REQUIRED header, decoded**

```json
{
  "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](https://settlens.com/learn/x402-v2-headers) page.

## Migration steps for resource servers

1. **Send the terms in the PAYMENT-REQUIRED header.** Answer 402 with a Base64-encoded `PaymentRequired` object, `x402Version` 2, in `PAYMENT-REQUIRED`. The V2 transport treats the response body as a server implementation concern, so clients must not need it.
2. **Move the resource out of each requirement.** Replace the per-requirement `resource`, `description` and `mimeType` with one top-level `resource` object, and set its `url` to the exact URL the client requested.
3. **Rename the amount and convert the networks.** `maxAmountRequired` becomes `amount`, still an integer string in [atomic units](https://settlens.com/learn/glossary#atomic-units). Network names become [CAIP-2](https://settlens.com/learn/glossary#caip-2) identifiers (table below).
4. **Read PAYMENT-SIGNATURE instead of X-PAYMENT.** The payload now carries the chosen requirement in `accepted`. Match it against your own `accepts` entries and send your own requirement, with `x402Version` 2, to `/verify` and `/settle`.
5. **Return PAYMENT-RESPONSE instead of X-PAYMENT-RESPONSE.** HTTP 200 with the settlement result on success, HTTP 402 with `success: false` when settlement fails.
6. **Declare and enforce the payment flow.** When an option settles before the handler runs (`upfront` or `escrow`), V2 requires `extra.paymentFlow` in it. Servers must reject transfer method and payment flow combinations they do not support.

_V1 network names and their CAIP-2 identifiers_

| 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-REQUIRED` case-insensitively, Base64-decode it and parse the JSON.
- **Check the binding.** `resource.url` should equal the URL you requested.
- **Echo the whole requirement.** Put the chosen `accepts` entry in `accepted`, the signed data in `payload`, and send it in `PAYMENT-SIGNATURE`. Echo any `extensions` you received: you may add information but not remove it.
- **Skip what you do not recognize.** Clients must not build a payment for a `paymentFlow` they do not recognize, and should prefer `authorization` when a resource also offers `upfront` or `escrow`.
- **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](https://settlens.com/learn/agent-spending-policy) covers the full set of limits.
- **Read the outcome from PAYMENT-RESPONSE.** Treat `settlement_pending` as unresolved: reconcile on chain with the returned hash before paying again.

## Migration steps for facilitators

- List V2 kinds in `GET /supported`: `x402Version` 2 with CAIP-2 networks. A facilitator can list V1 and V2 kinds side by side, since each kind carries its own `x402Version`.
- Add the now-required `extensions` array and `signers` map, which pairs CAIP-2 patterns such as `eip155:*` with your public signer addresses.
- Keep `/verify` read-only: the V2 specification states it must not commit payment state or write on chain.
- Return `settlement_pending`, with a non-empty `transaction` and `network`, when a broadcast transaction cannot be confirmed in time. The [facilitator security guide](https://settlens.com/learn/x402-facilitator-security) 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:

**Passive scan of a V1-style endpoint (demo target)**

```text
$ 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:

**Passive scan of a V2 endpoint (demo target)**

```text
$ 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_requirements` when this page was built, the V1 example above got the decision `do_not_pay`, with `schema.payment_required`, `policy.network` and `policy.acceptable_option` failing.
- A facilitator scan (`settlens facilitator`) fails `facilitator.supported_schema` while `/supported` still has the V1 shape, without `extensions` and `signers`, and `facilitator.v2_capability` when it lists no `x402Version` 2 kind.

To check one header by hand, paste it into the [x402 payment request checker](https://settlens.com/tools/x402-checker).

To gate every deploy on these checks, see [CI gating](https://settlens.com/product/ci); the [check reference](https://settlens.com/docs/checks) 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.

## Sources

1. [x402 protocol specification, version 2](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v2.md) — x402 Foundation
2. [x402 protocol specification, version 1](https://github.com/x402-foundation/x402/blob/main/specs/x402-specification-v1.md) — x402 Foundation
3. [x402 HTTP transport, version 2](https://github.com/x402-foundation/x402/blob/main/specs/transports-v2/http.md) — x402 Foundation
4. [x402 HTTP transport, version 1](https://github.com/x402-foundation/x402/blob/main/specs/transports-v1/http.md) — x402 Foundation
5. [CAIP-2: Blockchain ID Specification](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-2.md) — Chain Agnostic Standards Alliance
