Documentation Index
Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
Use this file to discover all available pages before exploring further.
This guide helps you migrate from x402 V1 to V2 on Polygon. The V2 protocol
introduces standardized CAIP-2 network identifiers, updated HTTP headers, and a
modular @x402/* package layout.
Polygon facilitators on mainnet and
Amoy run x402 v2. V1 clients and
middleware will not work against these endpoints.
For Go, Python, and full upstream details, see the
official migration guide.
Overview
| Aspect | V1 | V2 |
|---|
| Payment header | X-PAYMENT | PAYMENT-SIGNATURE |
| Response header | X-PAYMENT-RESPONSE | PAYMENT-RESPONSE |
| Network format | String (polygon-amoy, polygon) | CAIP-2 (eip155:80002, eip155:137) |
| Version field | x402Version: 1 | x402Version: 2 |
| Packages | x402-fetch, x402-axios, x402-express | @x402/fetch, @x402/axios, @x402/express, @x402/core, @x402/evm |
For buyers
Before (V1)
import { wrapFetchWithPayment } from "x402-fetch";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygonAmoy } from "viem/chains";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
chain: polygonAmoy,
transport: http(),
});
const fetchWithPayment = wrapFetchWithPayment(fetch, walletClient);
const response = await fetchWithPayment("https://api.example.com/paid-endpoint");
After (V2)
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
client.register("eip155:*", new ExactEvmScheme(signer));
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
const response = await fetchWithPayment("https://api.example.com/paid-endpoint");
Key changes
- Package rename:
x402-fetch → @x402/fetch
- Wallet setup: Use
x402Client with .register() instead of passing a chain-bound walletClient
- Environment variable:
PRIVATE_KEY → EVM_PRIVATE_KEY
- Receipt header: Read
PAYMENT-RESPONSE via x402HTTPClient.getPaymentSettleResponse(), not decodeXPaymentResponse() on x-payment-response
For sellers
Before (V1)
import { paymentMiddleware } from "x402-express";
app.use(
paymentMiddleware(
"0xYourAddress",
{
"GET /weather": {
price: "$0.001",
network: "polygon-amoy",
config: { description: "Weather data" },
},
},
{ url: "https://x402-amoy.polygon.technology" }
)
);
After (V2)
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
const payTo = "0xYourAddress";
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://x402-amoy.polygon.technology",
});
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:80002",
payTo,
},
],
description: "Weather data",
mimeType: "application/json",
},
},
new x402ResourceServer(facilitatorClient).register(
"eip155:80002",
new ExactEvmScheme()
)
)
);
Key changes
- Package rename:
x402-express → @x402/express
- Configuration structure: Route config uses an
accepts array with explicit scheme, network, and payTo
- Network format:
polygon-amoy → eip155:80002, polygon → eip155:137
- Resource server: Create
x402ResourceServer with a facilitator client and register schemes with .register()
- Middleware signature: Pass
(routes, server) instead of (wallet, routes, facilitatorConfig)
Network identifier mapping
| V1 name | V2 CAIP-2 ID | Chain ID | Description |
|---|
polygon-amoy | eip155:80002 | 80002 | Polygon Amoy testnet |
polygon | eip155:137 | 137 | Polygon PoS mainnet |
base-sepolia | eip155:84532 | 84532 | Base Sepolia testnet |
base | eip155:8453 | 8453 | Base mainnet |
ethereum | eip155:1 | 1 | Ethereum mainnet |
sepolia | eip155:11155111 | 11155111 | Ethereum Sepolia testnet |
Package migration reference
| V1 package | V2 package(s) |
|---|
x402 | @x402/core |
x402-express | @x402/express |
x402-axios | @x402/axios |
x402-fetch | @x402/fetch |
x402-hono | @x402/hono |
x402-next | @x402/next |
| (built-in) | @x402/evm (EVM support) |
Install examples:
# Buyers
npm install @x402/fetch @x402/core @x402/evm viem
# Sellers (Express)
npm install @x402/express @x402/core @x402/evm express
If you implement custom HTTP handling, update header names:
// V1
const payment = req.header("X-PAYMENT");
res.setHeader("X-PAYMENT-RESPONSE", responseData);
// V2
const payment = req.header("PAYMENT-SIGNATURE");
res.setHeader("PAYMENT-RESPONSE", responseData);
Troubleshooting
Payment verification failures
- Use CAIP-2 network identifiers (
eip155:80002 or eip155:137), not polygon-amoy or polygon
- Verify your
payTo address is correct
- Confirm the facilitator URL matches the network:
- Amoy:
https://x402-amoy.polygon.technology
- Mainnet:
https://x402.polygon.technology
”Cannot find module” errors
Ensure you installed all V2 packages:
npm install @x402/axios @x402/core @x402/evm
# Sellers
npm install @x402/express @x402/core @x402/evm
Mixed V1/V2 compatibility
During migration, update both buyers and sellers to V2 when targeting Polygon
facilitators. Legacy V1 network strings and headers will fail against v2-only
endpoints.
Next steps