x402 Examples
September 9, 2026 · View on GitHub
x402 is an HTTP-native payment protocol: a resource server responds
with 402 Payment Required, the client signs a payment and retries. These examples show what
the CDP SDK adds on top:
- CDP-managed wallets — no private keys to store; wallets are provisioned and signed by CDP.
- Hosted facilitator —
createCdpFacilitatorClient()is a drop-in for a self-hosted facilitator. - Spend controls — per-payment and rolling caps, network/asset/payee allowlists, and an approaching-limit callback.
- Builder codes — optional
builderCodeonCdpX402Client/createX402Serverfor on-chain attribution (son the client,aon the server).
Prerequisites
Complete the setup in the parent examples README first. In short, set these in
your .env:
CDP_API_KEY_IDCDP_API_KEY_SECRETCDP_WALLET_SECRET
Funding
The client examples pay in USDC on Base Sepolia, so the wallet needs testnet USDC before it can pay. Each client prints its EVM address on startup. Fund that address using any of:
- CDP Faucet (portal): https://portal.cdp.coinbase.com -> "Onchain Tools" -> "Faucet"
- Programmatically:
cdp.evm.requestFaucet({ address, network: "base-sepolia", token: "usdc" }) - Auto-fund shortcut: run
payForApi.tsonce withX402_FUND_FROM_FAUCET=true. That run requests USDC and exits; re-run it without the flag once the transfer confirms.
The CDP faucet funds the same wallets the CDP x402 facilitator settles against — no separate faucet is needed.
Clients
Run from the examples/typescript directory. Every client uses the same CDP primitive —
CdpX402Client — which extends the base x402Client, so it drops into any x402 transport wrapper
(fetch, axios, MCP) unchanged.
HTTP:
pnpm tsx x402/clients/payForApi.ts— pay for an x402-protected API over fetch (wrapFetchWithPayment). Prints the wallet address and supports theX402_FUND_FROM_FAUCET=trueauto-fund shortcut.pnpm tsx x402/clients/payForApiWithAxios.ts— the same flow over axios (wrapAxiosWithPayment). Only the transport differs.pnpm tsx x402/clients/payForApiWithSpendControls.ts— fetch, plus per-payment and cumulative spend caps, anallowedNetworksallowlist, and anonApproachingLimitcallback.pnpm tsx x402/clients/x402DevMigration.ts— migrating from a self-managed private key, shown two ways: swappingx402ClientforCdpX402Client, and slotting a CDP signer into an existingx402Client.
MCP (connect to the MCP server below):
pnpm tsx x402/clients/mcp/simple.ts— clean example: wrap an MCP client withCdpX402ClientviawrapMCPClientWithPayment, then call a free and a paid tool.pnpm tsx x402/clients/mcp/chatbot.ts— an interactive chatbot where Claude (Anthropic SDK) decides when to call the paid MCP tools and the CDP wallet settles payment automatically. NeedsANTHROPIC_API_KEY.
Servers
Each server is a self-contained workspace package with its own dependencies, so it runs differently
from the client examples — install and start it from its own directory. They fall back to the
shared examples/typescript/.env, so there is no second copy of your credentials to maintain.
Express and Hono serve a paid GET /report on http://localhost:8402; the Next.js server serves
GET /api/report on the same port. Every server settles on Base Sepolia so the clients above can
pay it. APPROACH selects the CDP wiring:
APPROACH=1— dropcreateCdpFacilitatorClient()into an x402 server you already have. NeedsCDP_API_KEY_ID,CDP_API_KEY_SECRET, andPAY_TO; no wallet secret, because the address you supply receives the payments.APPROACH=2(default) — thecreateX402Serverone-liner with inline routes, which also provisions the receiver wallet. NeedsCDP_WALLET_SECRETas well, and prints the provisioned addresses instead of usingPAY_TO.APPROACH=3(Express only) — the same one-liner reading its routes fromx402.config.json.x402.config.schema.jsonin the same directory documents every field. Keep credentials in env vars rather than the file.
# Express
cd x402/servers/express && pnpm install && APPROACH=2 pnpm start
# Hono (identical CDP wiring, different framework)
cd x402/servers/hono && pnpm install && APPROACH=2 pnpm start
# Next.js (App Router; withX402 on GET /api/report)
cd x402/servers/next && pnpm install && PAY_TO=0x... pnpm dev
Every server listens on its own default port and honors PORT, so pass PORT on the command line
to run two at once. The Next.js example is the exception to the shared-.env fallback: Next loads
env files itself, from x402/servers/next.
Every route declared through createX402Server — any of the three approaches above — is
discoverable in the CDP Bazaar automatically once it settles a real payment through the CDP
Facilitator; there's no separate wiring or registration step. See
Get discovered for how to add richer
discovery metadata to a route.
The Express server's Approach 2 additionally exposes GET /usage, which demonstrates the upto
scheme (usage-based billing): the client authorizes a ceiling of $0.10 and the handler settles
only the amount actually used via setSettlementOverrides. createX402Server auto-registers the
upto scheme, so the route just sets scheme: "upto". Pay it with the existing fetch client —
CdpX402Client handles upto automatically — by pointing it at the route:
X402_API_URL=http://localhost:8402/usage pnpm tsx x402/clients/payForApi.ts
MCP server — exposes paid tools over SSE using the CDP hosted facilitator and a CDP-managed receiver wallet:
cd x402/servers/mcp && pnpm install && pnpm start # http://localhost:4022
It provisions a CDP receiver wallet (so it needs CDP_WALLET_SECRET, or set PAY_TO to skip
provisioning) and serves generate_report (paid, $0.01) and ping (free). Point the MCP clients at
it with MCP_SERVER_URL (defaults to http://localhost:4022).
Scheme + network coverage matrix
x402/clients/payForSchemes.ts is a CLI harness (not a fixed demo like payForApi.ts) for driving
every scheme/network combination CdpX402Client supports against these example servers. It's
entirely environment-variable driven — see X402_API_URL and X402_PREFERRED_NETWORK in
Environment variables — and exits non-zero on failure, so it doubles as
a pass/fail check. exact, upto, and authCapture are all registered by default (matching
CdpX402Client's own defaults), so no scheme opt-in flag is needed.
| Scheme | Network | Server | Command |
|---|---|---|---|
exact | Base Sepolia | CDP Express (GET /report) | X402_API_URL=http://localhost:8402/report X402_PREFERRED_NETWORK=eip155:84532 pnpm tsx x402/clients/payForSchemes.ts |
exact | Solana Devnet | CDP Express (GET /report) | X402_API_URL=http://localhost:8402/report X402_PREFERRED_NETWORK=solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 pnpm tsx x402/clients/payForSchemes.ts |
upto | Base Sepolia | CDP Express (GET /usage) | X402_API_URL=http://localhost:8402/usage X402_PREFERRED_NETWORK=eip155:84532 pnpm tsx x402/clients/payForSchemes.ts |
auth-capture | Base Sepolia | CDP Express (GET /auth-capture-mock, smoke test only) | X402_API_URL=http://localhost:8402/auth-capture-mock pnpm tsx x402/clients/payForSchemes.ts |
GET /report accepts Base Sepolia and Solana Devnet by default, so X402_PREFERRED_NETWORK forces
the client's network choice via a registered PaymentPolicy — without it, CdpX402Client picks
whichever the underlying x402Client selects first. GET /usage is Base Sepolia only —
createX402Server's upto support doesn't extend to Solana yet (see below).
exact on Base + Solana, upto on Base run against the CDP Express server from the
Servers section above (cd x402/servers/express && APPROACH=2 pnpm start) — no extra
setup beyond funding the wallet (see Funding; fund the Solana address too, via
cdp.solana.requestFaucet({ address, token: "usdc" | "sol" }), for the Solana Devnet case).
upto on Solana is supported by CdpX402Client (registered by default whenever a route
requests it), but not by createX402Server: the resource server would need to sign an
arbitrary-bytes settlement voucher, and CDP's Solana account signing API can only sign UTF-8 text
today. Tracked separately; no example route exercises it until server-side support lands.
auth-capture on Base has no facilitator or resource-server support yet (client-only, on by
default alongside exact/upto; see the CDP SDK's README.md). GET /auth-capture-mock on the
CDP Express server is a smoke test, not a real payment route: it returns 402 with hand-built
auth-capture payment requirements, and once the client signs and retries with a
PAYMENT-SIGNATURE header, responds 501 to confirm the payload was received without claiming
settlement actually happened. Running payForSchemes.ts against it therefore exits non-zero on
that 501 — that's expected; it's proof CdpX402Client.createPaymentPayload produces a valid
auth-capture payload, not an end-to-end settlement test.
batch-settlement on Base is supported by CdpX402Client (opt-in via
scheme: { batchSettlement: true }) but isn't covered by this CLI matrix yet — it needs a
long-lived client process to exercise its off-chain voucher-channel reuse correctly, which doesn't
fit this harness's one-shot-per-command model. Tracked separately.
Environment variables
CDP_API_KEY_ID,CDP_API_KEY_SECRET,CDP_WALLET_SECRET— CDP credentials (see Prerequisites).ANTHROPIC_API_KEY— (MCP chatbot only) Claude API key forx402/clients/mcp/chatbot.ts.ANTHROPIC_MODEL— (MCP chatbot only) override the Claude model. Defaults toclaude-sonnet-4-5.X402_API_URL— override the x402-protected URL the HTTP clients call. Defaults tohttps://x402.vercel.app/protected.X402_FUND_FROM_FAUCET— set totruefor onepayForApi.tsorpayForSchemes.tsrun to request USDC from the faucet. That run exits without paying. Only funds Base Sepolia EVM USDC — fund the Solana Devnet payer separately (e.g. via the Solana faucet) before running the Solana rows of the matrix.X402_PREFERRED_NETWORK— (payForSchemes.tsonly) a CAIP-2 network id (e.g.eip155:84532,solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1) to force on a dual-network route likeGET /report, via a registeredPaymentPolicy. Omit to let the client pick its default.MCP_SERVER_URL— (MCP clients) the MCP server URL. Defaults tohttp://localhost:4022.CDP_X402_CLIENT_ENVIRONMENT—"production"(default, Base mainnet) or"development"(Base Sepolia). Controls which Base networkCdpX402Clientprescribes by default; overridden by theenvironmentconfig option. These examples passenvironment: "development"explicitly, so this env var isn't required to run them as-is.CDP_X402_SERVER_ENVIRONMENT— thecreateX402Serverequivalent of the above. The servers also passenvironment: "development"explicitly, so this env var isn't required either.- Non-Base RPC URLs — pass them via the
networkSchemesconfig option onCdpX402Client, e.g.new CdpX402Client({ networkSchemes: [{ network: "polygon", rpcUrl: "https://your-rpc-provider.example.com/polygon", scheme: { exact: true } }] }). Base and Base Sepolia resolve an RPC automatically via your CDP project's node endpoint; CDP doesn't host RPCs for other networks, so those require an explicitrpcUrlfrom your own RPC provider. APPROACH— (Express and Hono) which CDP wiring to run:1,2(default), or3(Express only).PAY_TO— (servers) the EVM address that should receive payments (required for Approach 1 and the Next.js server; optional for the MCP server).PORT— (servers) override the listen port. Defaults to8402for the HTTP servers and4022for the MCP server. Set it per command rather than in.env, where it would move every server.