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
Update packages
Replace legacy packages with new modular packages
Update network identifiers
Change to CAIP-2 format (e.g., base-sepolia → eip155:84532)
Update headers
Change header names (X-PAYMENT → PAYMENT-SIGNATURE)
Update code patterns
Migrate to new middleware and client patterns
Package Changes
For Sellers (Server-Side)
| v1 Package | v2 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 Package | v2 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 Network | v2 Network (CAIP-2) |
|---|
base-sepolia | eip155:84532 |
base | eip155:8453 |
solana-devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 |
solana | solana: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
| v1 Header | v2 Header | Purpose |
|---|
X-PAYMENT | PAYMENT-SIGNATURE | Client → Server: Signed payment payload |
X-PAYMENT-RESPONSE | PAYMENT-RESPONSE | Server → Client: Settlement confirmation |
| (body) | PAYMENT-REQUIRED | Server → 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 Field | v2 Field | Notes |
|---|
maxAmountRequired | amount | Renamed |
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:
- Wait for the v2 Python SDK - Check the x402 Discord for updates
- Migrate to TypeScript - Use the Node.js SDK with full v2 support
- Migrate to Go - Use the Go SDK with full v2 support
- Continue with v1 - v1 continues to work, though v2 is recommended
Testing Your Migration
- Testnet First: Always test on testnet (
eip155:84532 for Base Sepolia)
- Verify Headers: Ensure
PAYMENT-SIGNATURE and PAYMENT-RESPONSE headers are used
- Check Network Format: Confirm CAIP-2 identifiers are correct
- 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