Documentation Index
Fetch the complete documentation index at: https://docs.x402.org/llms.txt
Use this file to discover all available pages before exploring further.
Overview
| Aspect | V1 | V2 |
|---|
| Payment Header | X-PAYMENT | PAYMENT-SIGNATURE |
| Response Header | X-PAYMENT-RESPONSE | PAYMENT-RESPONSE |
| Network Format | String (base-sepolia) | CAIP-2 (eip155:84532) |
| Version Field | x402Version: 1 | x402Version: 2 |
| Packages | x402, x402-express, x402-axios | @x402/core, @x402/express, @x402/axios, @x402/evm |
For Buyers
Before (V1)
import { withPaymentInterceptor } from "x402-axios";
import { createWalletClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { baseSepolia } from "viem/chains";
import axios from "axios";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
account,
chain: baseSepolia,
transport: http(),
});
// V1 pattern
const api = withPaymentInterceptor(
axios.create({ baseURL: "https://api.example.com" }),
walletClient,
);
const response = await api.get("/paid-endpoint");
import os
from eth_account import Account
from x402.clients.httpx import x402HttpxClient
# V1 pattern
account = Account.from_key(os.getenv("PRIVATE_KEY"))
async with x402HttpxClient(account=account, base_url="https://api.example.com") as client:
response = await client.get("/protected-endpoint")
print(await response.aread())
After (V2)
import { x402Client, wrapAxiosWithPayment } from "@x402/axios";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import axios from "axios";
const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`);
// V2 pattern: Create client and register scheme using the builder pattern
const client = new x402Client();
client.register("eip155:*", new ExactEvmScheme(signer));
// Wrap axios with payment handling
const api = wrapAxiosWithPayment(
axios.create({ baseURL: "https://api.example.com" }),
client,
);
const response = await api.get("/paid-endpoint");
import asyncio
import os
from eth_account import Account
from x402 import x402Client
from x402.http import x402HTTPClient
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client
async def main() -> None:
# V2 pattern: Create client and register scheme separately
client = x402Client()
account = Account.from_key(os.getenv("EVM_PRIVATE_KEY"))
register_exact_evm_client(client, EthAccountSigner(account))
http_client = x402HTTPClient(client)
async with x402HttpxClient(client) as http:
response = await http.get("https://api.example.com/paid-endpoint")
await response.aread()
print(f"Response: {response.text}")
if response.is_success:
settle_response = http_client.get_payment_settle_response(
lambda name: response.headers.get(name)
)
print(f"Payment settled: {settle_response}")
asyncio.run(main())
Key Changes
- Package rename:
x402-axios → @x402/axios
- Function rename:
withPaymentInterceptor → wrapAxiosWithPayment
- Wallet setup: Use
x402Client with .register() builder pattern instead of passing wallet directly
- No chain-specific configuration: The V2 client automatically handles network selection based on payment requirements
- Import path changes:
x402.clients.httpx → x402.http.clients
- Signer wrapper: Wrap
eth_account.Account with EthAccountSigner
- Client construction: Create
x402Client() first, then register schemes
- Environment variable:
PRIVATE_KEY → EVM_PRIVATE_KEY
- Async/Sync variants: Use
x402Client for httpx (async), x402ClientSync for requests (sync)
For Sellers
Before (V1)
import { paymentMiddleware, FacilitatorConfig } from "x402-express";
import express from "express";
const app = express();
const facilitatorConfig: FacilitatorConfig = {
url: "https://x402.org/facilitator",
};
app.use(
paymentMiddleware(facilitatorConfig, {
"GET /weather": {
price: "$0.001",
network: "base-sepolia", // V1 string format
config: {
description: "Get weather data",
},
},
}),
);
from typing import Any, Dict
from fastapi import FastAPI
from x402.fastapi.middleware import require_payment
app = FastAPI()
# V1 pattern
app.middleware("http")(
require_payment(
path="/weather",
price="$0.001",
pay_to_address="0xYourAddress",
network="base-sepolia", # V1 string identifier
)
)
@app.get("/weather")
async def get_weather() -> Dict[str, Any]:
return {"report": {"weather": "sunny", "temperature": 70}}
After (V2)
import express from "express";
import { paymentMiddleware } from "@x402/express";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
const app = express();
const payTo = "0xYourAddress";
// V2 pattern: Create facilitator client and resource server
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://x402.org/facilitator"
});
const server = new x402ResourceServer(facilitatorClient);
server.register("eip155:*", new ExactEvmScheme());
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:84532", // V2 CAIP-2 format
payTo,
},
],
description: "Get weather data",
mimeType: "application/json",
},
},
server,
),
);
from typing import Any
from fastapi import FastAPI
from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption
from x402.http.middleware.fastapi import PaymentMiddlewareASGI
from x402.http.types import RouteConfig
from x402.mechanisms.evm.exact import ExactEvmServerScheme
from x402.server import x402ResourceServer
app = FastAPI()
# V2 pattern: Create facilitator client and resource server
facilitator = HTTPFacilitatorClient(
FacilitatorConfig(url="https://x402.org/facilitator")
)
server = x402ResourceServer(facilitator)
server.register("eip155:84532", ExactEvmServerScheme())
# V2: Route config uses accepts array with explicit scheme, network, and pay_to
routes: dict[str, RouteConfig] = {
"GET /weather": RouteConfig(
accepts=[
PaymentOption(
scheme="exact",
pay_to="0xYourAddress",
price="$0.001",
network="eip155:84532", # V2 CAIP-2 format
),
],
mime_type="application/json",
description="Get weather data",
),
}
app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server)
@app.get("/weather")
async def get_weather() -> dict[str, Any]:
return {"report": {"weather": "sunny", "temperature": 70}}
Key Changes
- Package rename:
x402-express → @x402/express
- Configuration structure: Route config now uses
accepts array with explicit scheme, network, and payTo
- Network format:
base-sepolia → eip155:84532 (CAIP-2 standard)
- Resource server: Create
x402ResourceServer with facilitator client and register schemes using the .register() builder pattern
- Price recipient: Explicitly specify
payTo address per route
- Import path changes:
x402.fastapi.middleware → x402.http.middleware.fastapi
- Middleware pattern:
require_payment decorator → PaymentMiddlewareASGI class
- Configuration structure: Route config now uses
RouteConfig and PaymentOption Pydantic models
- Network format:
base-sepolia → eip155:84532 (CAIP-2 standard)
- Resource server: Create
x402ResourceServer and register schemes explicitly
- Type hints: Use modern Python type hints (
dict[str, Any] instead of Dict[str, Any])
- Async/Sync variants: Use
x402ResourceServer + HTTPFacilitatorClient for FastAPI (async), use x402ResourceServerSync + HTTPFacilitatorClientSync for Flask (sync)
Network Identifier Mapping
| V1 Name | V2 CAIP-2 ID | Chain ID | Description |
|---|
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 |
solana-devnet | solana:devnet | - | Solana Devnet |
solana | solana:mainnet | - | Solana Mainnet |
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) |
| (built-in) | @x402/svm (Solana support) |
| V1 Import Path | V2 Import Path |
|---|
x402.clients.httpx | x402.http.clients.x402HttpxClient |
x402.clients.requests | x402.http.clients.x402_requests |
x402.fastapi.middleware | x402.http.middleware.fastapi |
x402.flask.middleware | x402.http.middleware.flask |
x402.facilitator | x402.http.HTTPFacilitatorClient |
| (new) | x402.mechanisms.evm.EthAccountSigner |
| (new) | x402.mechanisms.evm.exact.register_exact_evm_client |
| (new) | x402.mechanisms.svm.KeypairSigner |
| (new) | x402.mechanisms.svm.exact.register_exact_svm_client |
| (new) | x402.server.x402ResourceServer |
Installation with extras:# V1
pip install x402
# V2 - install with specific extras
pip install "x402[httpx]" # For async HTTP clients
pip install "x402[requests]" # For sync HTTP clients
pip install "x402[fastapi]" # For FastAPI servers
pip install "x402[flask]" # For Flask servers
pip install "x402[svm]" # For Solana support
If you’re implementing custom HTTP handling, update your 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);
# V1
payment = request.headers.get("X-PAYMENT")
response.headers["X-PAYMENT-RESPONSE"] = response_data
# V2
payment = request.headers.get("PAYMENT-SIGNATURE")
response.headers["PAYMENT-RESPONSE"] = response_data
Troubleshooting
”Cannot find module” errors
Ensure you’ve installed all V2 packages:# For buyers
npm install @x402/axios @x402/evm
# For sellers (Express)
npm install @x402/express @x402/core @x402/evm
“ModuleNotFoundError” errors
Ensure you’ve installed the x402 package with the correct extras:# For async HTTP clients (httpx)
pip install "x402[httpx]"
# For sync HTTP clients (requests)
pip install "x402[requests]"
# For FastAPI servers
pip install "x402[fastapi]"
# For Flask servers
pip install "x402[flask]"
# For Solana support
pip install "x402[svm]"
Payment verification failures
- Check you’re using CAIP-2 network identifiers (
eip155:84532 not base-sepolia)
- Verify your
payTo address is correctly configured
- Ensure the facilitator URL is correct for your network (testnet vs mainnet)
Mixed V1/V2 compatibility
The facilitator supports both V1 and V2 protocols. During migration, your V2 server can still accept payments from V1 clients, but we recommend updating clients to V2 for full feature support.
Next Steps