x402 Sell Skill
Enable AI agents to sell resources and accept USDC payments for API endpoints using x402.
Overview
x402 allows servers to payment-gate endpoints. When clients request a protected resource without payment, the server returns HTTP 402 with payment requirements. The server uses a Facilitator (like Coinbase CDP) to verify and settle payments on-chain.
Quick Start
1. Setup Receiving Wallet
Create a wallet to receive payments.
Non-interactive CLI commands (for AI agents):
# EVM wallet (Base, Ethereum, Avalanche) - pipes "1" to select EOA
echo "1" | npx add-wallet evm
# Solana wallet
npx add-wallet sol
# Top up with testnet USDC (for testing payments)
npx add-wallet topup testnet
This creates a .env file with WALLET_ADDRESS and WALLET_PRIVATE_KEY.
Use the address in your code:
// Read from .env or use directly
const payTo = process.env.WALLET_ADDRESS; // From .env file
// or
const payTo = "0xYourWalletAddress"; // EVM address
// or
const payTo = "YourSolanaAddress"; // Solana address
2. Install Packages
# Express
npm install @x402/express @x402/core @x402/evm
# Next.js
npm install @x402/next @x402/core @x402/evm
# Hono
npm install @x402/hono @x402/core @x402/evm
# For Solana support:
npm install @x402/svm
3. Add Payment Middleware (Express)
import express from "express";
import { paymentMiddleware } from "@x402/express";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";
const app = express();
const payTo = "0xYourAddress";
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://api.cdp.coinbase.com/platform/v2/x402" // Mainnet (default)
// url: "https://x402.org/facilitator" // Testnet
});
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:8453", // Base Mainnet (use eip155:84532 for testnet)
payTo,
},
],
description: "Get weather data",
mimeType: "application/json",
},
},
server,
),
);
app.get("/weather", (req, res) => {
res.json({ weather: "sunny", temperature: 70 });
});
app.listen(4021);
Facilitator URLs
Default: Mainnet (CDP) - Use for production payments.
| Environment | URL |
|---|---|
| Mainnet (CDP) | https://api.cdp.coinbase.com/platform/v2/x402 (default) |
| Testnet | https://x402.org/facilitator |
Price Format
The price field uses dollar notation. SDK converts to atomic units automatically.
| Price | Meaning | Atomic Units |
|---|---|---|
"$0.001" | 0.1 cents | 1000 |
"$0.01" | 1 cent | 10000 |
"$0.10" | 10 cents | 100000 |
"$1.00" | 1 dollar | 1000000 |
Network Identifiers (CAIP-2)
Default: Base Mainnet (eip155:8453) - Use for production payments.
| Network | CAIP-2 ID | Environment |
|---|---|---|
| Base Mainnet | eip155:8453 | Production (default) |
| Avalanche C-Chain | eip155:43114 | Production |
| Solana Mainnet | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | Production |
| Base Sepolia | eip155:84532 | Testnet |
| Avalanche Fuji | eip155:43113 | Testnet |
| Solana Devnet | solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 | Testnet |
USDC Token Addresses
| Network | USDC Contract Address |
|---|---|
Base Mainnet (eip155:8453) | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
Base Sepolia (eip155:84532) | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
Avalanche (eip155:43114) | 0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E |
| Solana Mainnet | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
Framework Examples
Next.js
// middleware.ts
import { paymentProxy } from "@x402/next";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://api.cdp.coinbase.com/platform/v2/x402" // Mainnet
});
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);
export const middleware = paymentProxy(
{
"/api/protected": {
accepts: [{ scheme: "exact", price: "$0.01", network: "eip155:8453", payTo: "0xYour" }],
description: "Protected content",
},
},
server,
);
export const config = { matcher: ["/api/protected/:path*"] };
Hono
import { Hono } from "hono";
import { paymentMiddleware } from "@x402/hono";
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { registerExactEvmScheme } from "@x402/evm/exact/server";
const app = new Hono();
const facilitatorClient = new HTTPFacilitatorClient({ url: "https://api.cdp.coinbase.com/platform/v2/x402" });
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);
app.use(
paymentMiddleware(
{
"/paid": {
accepts: [{ scheme: "exact", price: "$0.10", network: "eip155:8453", payTo: "0xYour" }],
},
},
server,
),
);
app.get("/paid", (c) => c.json({ message: "Premium content" }));
Go (Gin)
import (
x402 "github.com/coinbase/x402/go"
x402http "github.com/coinbase/x402/go/http"
ginmw "github.com/coinbase/x402/go/http/gin"
evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server"
"github.com/gin-gonic/gin"
)
func main() {
r := gin.Default()
facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
URL: "https://api.cdp.coinbase.com/platform/v2/x402", // Mainnet
})
r.Use(ginmw.X402Payment(ginmw.Config{
Routes: x402http.RoutesConfig{
"GET /weather": {
Accepts: x402http.PaymentOptions{
{Scheme: "exact", Price: "$0.001", Network: "eip155:8453", PayTo: "0xYour"},
},
Description: "Weather data",
},
},
Facilitator: facilitatorClient,
Schemes: []ginmw.SchemeConfig{
{Network: "eip155:8453", Server: evm.NewExactEvmScheme()},
},
}))
r.GET("/weather", func(c *gin.Context) {
c.JSON(200, gin.H{"weather": "sunny"})
})
r.Run(":4021")
}
Python (FastAPI)
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()
pay_to = "0xYourAddress"
facilitator = HTTPFacilitatorClient(
FacilitatorConfig(url="https://api.cdp.coinbase.com/platform/v2/x402") # Mainnet
)
server = x402ResourceServer(facilitator)
server.register("eip155:8453", ExactEvmServerScheme())
routes = {
"GET /weather": RouteConfig(
accepts=[PaymentOption(scheme="exact", pay_to=pay_to, price="$0.001", network="eip155:8453")],
description="Weather data",
),
}
app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server)
@app.get("/weather")
async def get_weather():
return {"weather": "sunny", "temperature": 70}
Multi-Network Support
Accept payments on both EVM and Solana (mainnet):
import { registerExactEvmScheme } from "@x402/evm/exact/server";
import { registerExactSvmScheme } from "@x402/svm/exact/server";
const server = new x402ResourceServer(facilitatorClient);
registerExactEvmScheme(server);
registerExactSvmScheme(server);
app.use(
paymentMiddleware(
{
"GET /data": {
accepts: [
{ scheme: "exact", price: "$0.01", network: "eip155:8453", payTo: "0xYourEvmAddress" }, // Base Mainnet
{ scheme: "exact", price: "$0.01", network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", payTo: "YourSolanaAddress" }, // Solana Mainnet
],
},
},
server,
),
);
Bazaar Discovery
Make your endpoint discoverable:
import { declareDiscoveryExtension } from "@x402/extensions/bazaar";
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [{ scheme: "exact", price: "$0.001", network: "eip155:8453", payTo }], // Base Mainnet
description: "Real-time weather data",
mimeType: "application/json",
extensions: {
...declareDiscoveryExtension({
input: { city: "San Francisco" },
inputSchema: { properties: { city: { type: "string" } }, required: ["city"] },
output: { example: { city: "San Francisco", weather: "foggy" } },
}),
},
},
},
server,
),
);
Server Payment Flow
- Client requests protected endpoint
- Server returns 402 Payment Required with
PAYMENT-REQUIREDheader - Client creates payment and sends with
PAYMENT-SIGNATUREheader - Server verifies payment via Facilitator (
/verify) - Server executes endpoint handler
- Server settles payment via Facilitator (
/settle) - Server returns response with
PAYMENT-RESPONSEheader
Testing Your Server
curl -i http://localhost:4021/weather
# Expected: HTTP/1.1 402 Payment Required
# PAYMENT-REQUIRED: <base64-encoded payment requirements>
Setup Checklist
- Get a wallet address - Run
echo "1" | npx add-wallet evm(non-interactive) - Note the address - Check
.envforWALLET_ADDRESSto use aspayTo - Choose network - Use
eip155:8453(Base Mainnet) for production, oreip155:84532(Base Sepolia) for testing - Set price - Use dollar notation (
"$0.001") - Configure facilitator - Use
https://api.cdp.coinbase.com/platform/v2/x402for mainnet (orhttps://x402.org/facilitatorfor testnet) - Add middleware - Protect routes with payment requirements
- Test - curl should return 402 with payment instructions
Key Packages
TypeScript
@x402/express- Express.js middleware@x402/next- Next.js middleware@x402/hono- Hono middleware@x402/core- Core server utilities@x402/evm- EVM scheme@x402/svm- Solana scheme
Go
github.com/coinbase/x402/go- Core packagegithub.com/coinbase/x402/go/http/gin- Gin middleware
Python
x402[fastapi]- FastAPI supportx402[flask]- Flask support