Skip to main content
This guide helps you migrate your x402 integration from v1 to v2. The v2 release introduces improved package structure, standardized network identifiers, and updated HTTP headers.
v2 is now the recommended version. While v1 continues to work, we encourage all users to migrate to v2 for the latest features and improvements.

What’s New in v2

  • CAIP-2 Network Identifiers: Industry-standard chain identification
  • Modular Package Structure: Separate packages for core, mechanisms, and frameworks
  • New HTTP Headers: Standardized header names
  • Extensions System: Bazaar discovery, authentication extensions
  • Go SDK: Full Go support alongside TypeScript

Quick Migration Checklist

1

Update packages

Replace legacy packages with new modular packages
2

Update network identifiers

Change to CAIP-2 format (e.g., base-sepoliaeip155:84532)
3

Update headers

Change header names (X-PAYMENTPAYMENT-SIGNATURE)
4

Update code patterns

Migrate to new middleware and client patterns

Package Changes

For Sellers (Server-Side)

v1 Packagev2 Packages
x402-express@x402/express + @x402/evm or @x402/svm
x402-next@x402/next + @x402/evm or @x402/svm
x402-hono@x402/hono + @x402/evm or @x402/svm
@coinbase/x402@coinbase/x402@^2.0.0 (upgrade)
Install v2 packages:
# Express
npm uninstall x402-express
npm install @x402/express @coinbase/x402@^2.0.0

# Next.js
npm uninstall x402-next
npm install @x402/next @coinbase/x402@^2.0.0

# Hono
npm uninstall x402-hono
npm install @x402/hono @coinbase/x402@^2.0.0

# For EVM (Ethereum) support, add:
npm install @x402/evm

# For SVM (Solana) support, add:
npm install @x402/svm

For Buyers (Client-Side)

v1 Packagev2 Packages
x402-fetch@x402/fetch + @x402/evm or @x402/svm
x402-axios@x402/axios + @x402/evm or @x402/svm
Install v2 packages:
# Fetch
npm uninstall x402-fetch
npm install @x402/fetch

# Axios
npm uninstall x402-axios
npm install @x402/axios

# For EVM (Ethereum) support, add:
npm install @x402/evm

# For SVM (Solana) support, add:
npm install @x402/svm

Network Identifier Changes (CAIP-2)

v2 uses CAIP-2 format for network identifiers:
v1 Networkv2 Network (CAIP-2)
base-sepoliaeip155:84532
baseeip155:8453
solana-devnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
solanasolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
Format explanation:
  • EVM: eip155:{chainId} where chainId is the network’s chain ID (e.g., 8453 for Base mainnet, 84532 for Base Sepolia)
  • Solana: solana:{genesisHash} using the truncated genesis hash of the cluster

HTTP Header Changes

v1 Headerv2 HeaderPurpose
X-PAYMENTPAYMENT-SIGNATUREClient → Server: Signed payment payload
X-PAYMENT-RESPONSEPAYMENT-RESPONSEServer → Client: Settlement confirmation
(body)PAYMENT-REQUIREDServer → Client: Payment requirements (base64)
v2 libraries check for both v1 and v2 header names for backward compatibility, but you should use the v2 headers for new implementations.

Schema Changes

PaymentRequirements

v1 Fieldv2 FieldNotes
maxAmountRequiredamountRenamed
resource(moved)Now in ResourceInfo
description(moved)Now in ResourceInfo
mimeType(moved)Now in ResourceInfo

Route Configuration

v1:
{
  "GET /weather": {
    price: "$0.001",
    network: "base-sepolia",
    config: {
      description: "Weather data",
      mimeType: "application/json",
    }
  }
}
v2:
{
  "GET /weather": {
    accepts: [
      {
        scheme: "exact",
        price: "$0.001",
        network: "eip155:84532",
        payTo: "0xYourAddress",
      },
    ],
    description: "Weather data",
    mimeType: "application/json",
  }
}
Key changes:
  • Payment options moved to accepts array
  • payTo included in each payment option
  • config flattened to top level
  • Network uses CAIP-2 format

Code Migration Examples

Seller: Express Middleware

v1:
import { paymentMiddleware, Network } from "x402-express";
import { facilitator } from "@coinbase/x402";

app.use(paymentMiddleware(
  "0xYourAddress",
  {
    "GET /weather": {
      price: "$0.001",
      network: "base-sepolia",
      config: { description: "Weather data" }
    },
  },
  { url: "https://x402.org/facilitator" }
));
v2:
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});

const server = new x402ResourceServer(facilitatorClient)
  .register("eip155:84532", new ExactEvmScheme());

app.use(
  paymentMiddleware(
    {
      "GET /weather": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.001",
            network: "eip155:84532",
            payTo: "0xYourAddress",
          },
        ],
        description: "Weather data",
        mimeType: "application/json",
      },
    },
    server,
  ),
);

Seller: Next.js Middleware

v1:
import { paymentMiddleware } from "x402-next";
import { facilitator } from "@coinbase/x402";

export const middleware = paymentMiddleware(
  "0xYourAddress",
  { "/api/protected": { price: "$0.01", network: "base" } },
  facilitator,
);
v2:
import { paymentProxy, x402ResourceServer } from "@x402/next";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";

const facilitatorClient = new HTTPFacilitatorClient({
  url: "https://x402.org/facilitator"
});

const server = new x402ResourceServer(facilitatorClient)
  .register("eip155:8453", new ExactEvmScheme());

export const middleware = paymentProxy(
  {
    "/api/protected": {
      accepts: [
        {
          scheme: "exact",
          price: "$0.01",
          network: "eip155:8453",
          payTo: "0xYourAddress",
        },
      ],
      description: "Protected endpoint",
    },
  },
  server,
);

Buyer: Fetch Client

v1:
import { wrapFetchWithPayment, decodeXPaymentResponse } from "x402-fetch";

const fetchWithPayment = wrapFetchWithPayment(fetch, account);
const response = await fetchWithPayment(url);
const paymentResponse = decodeXPaymentResponse(response);
v2:
import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(privateKey);

const client = new x402Client();
registerExactEvmScheme(client, { signer });

const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPayment(url);

// Get payment receipt
const httpClient = new x402HTTPClient(client);
const paymentResponse = httpClient.getPaymentSettleResponse(
  (name) => response.headers.get(name)
);

Buyer: Axios Client

v1:
import { withPaymentInterceptor } from "x402-axios";

const client = withPaymentInterceptor(axios.create({ baseURL }), account);
v2:
import { x402Client, withPaymentInterceptor } from "@x402/axios";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(privateKey);

const x402client = new x402Client();
registerExactEvmScheme(x402client, { signer });

const client = withPaymentInterceptor(axios.create({ baseURL }), x402client);

Multi-Network Support (New in v2)

v2 makes it easy to support multiple networks:

Server-Side

import { ExactEvmScheme } from "@x402/evm/exact/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";

const server = new x402ResourceServer(facilitatorClient)
  .register("eip155:8453", new ExactEvmScheme())
  .register("eip155:84532", new ExactEvmScheme())
  .register("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", new ExactSvmScheme());

// Endpoint accepting multiple networks
{
  "GET /api": {
    accepts: [
      { scheme: "exact", price: "$0.01", network: "eip155:8453", payTo: evmAddress },
      { scheme: "exact", price: "$0.01", network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", payTo: solanaAddress },
    ],
  },
}

Client-Side

import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { registerExactSvmScheme } from "@x402/svm/exact/client";

const client = new x402Client();
registerExactEvmScheme(client, { signer: evmSigner });
registerExactSvmScheme(client, { signer: svmSigner });

// Client automatically handles both EVM and Solana payments

Python Users

The Python SDK is currently under development for x402 v2. For immediate v2 support, use TypeScript or Go.
If you’re currently using Python with v1, you have several options:
  1. Wait for the v2 Python SDK - Check the x402 Discord for updates
  2. Migrate to TypeScript - Use the Node.js SDK with full v2 support
  3. Migrate to Go - Use the Go SDK with full v2 support
  4. Continue with v1 - v1 continues to work, though v2 is recommended

Testing Your Migration

  1. Testnet First: Always test on testnet (eip155:84532 for Base Sepolia)
  2. Verify Headers: Ensure PAYMENT-SIGNATURE and PAYMENT-RESPONSE headers are used
  3. Check Network Format: Confirm CAIP-2 identifiers are correct
  4. Test Payment Flow: Complete a full payment cycle

Troubleshooting

Common Issues

“No scheme registered for network”
  • Use .register(network, scheme) to register a scheme for a specific CAIP-2 network identifier
  • Use .registerV1(network, scheme) to register a v1 backwards-compatible implementation
  • Verify the network identifier matches CAIP-2 format (e.g., eip155:8453 not base)
The helper functions registerExactEvmScheme() and registerExactSvmScheme() will register schemes on your behalf for convenience. However, they may over-register for networks you don’t need. If you want fine-grained control over which networks are registered, call .register() or .registerV1() directly.
Payment not processing
  • Check that headers use the v2 names
  • Verify the accepts array in route configuration
Response parsing fails
  • Use x402HTTPClient.getPaymentSettleResponse() instead of decodeXPaymentResponse()
  • Check for PAYMENT-RESPONSE header (not X-PAYMENT-RESPONSE)

Support