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 facilitatorcreateCdpFacilitatorClient() 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 builderCode on CdpX402Client / createX402Server for on-chain attribution (s on the client, a on the server).

Prerequisites

Complete the setup in the parent examples README first. In short, set these in your .env:

  • CDP_API_KEY_ID
  • CDP_API_KEY_SECRET
  • CDP_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.ts once with X402_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 the X402_FUND_FROM_FAUCET=true auto-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, an allowedNetworks allowlist, and an onApproachingLimit callback.
  • pnpm tsx x402/clients/x402DevMigration.ts — migrating from a self-managed private key, shown two ways: swapping x402Client for CdpX402Client, and slotting a CDP signer into an existing x402Client.

MCP (connect to the MCP server below):

  • pnpm tsx x402/clients/mcp/simple.ts — clean example: wrap an MCP client with CdpX402Client via wrapMCPClientWithPayment, 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. Needs ANTHROPIC_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:

  1. APPROACH=1 — drop createCdpFacilitatorClient() into an x402 server you already have. Needs CDP_API_KEY_ID, CDP_API_KEY_SECRET, and PAY_TO; no wallet secret, because the address you supply receives the payments.
  2. APPROACH=2 (default) — the createX402Server one-liner with inline routes, which also provisions the receiver wallet. Needs CDP_WALLET_SECRET as well, and prints the provisioned addresses instead of using PAY_TO.
  3. APPROACH=3 (Express only) — the same one-liner reading its routes from x402.config.json. x402.config.schema.json in 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.

SchemeNetworkServerCommand
exactBase SepoliaCDP Express (GET /report)X402_API_URL=http://localhost:8402/report X402_PREFERRED_NETWORK=eip155:84532 pnpm tsx x402/clients/payForSchemes.ts
exactSolana DevnetCDP Express (GET /report)X402_API_URL=http://localhost:8402/report X402_PREFERRED_NETWORK=solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1 pnpm tsx x402/clients/payForSchemes.ts
uptoBase SepoliaCDP Express (GET /usage)X402_API_URL=http://localhost:8402/usage X402_PREFERRED_NETWORK=eip155:84532 pnpm tsx x402/clients/payForSchemes.ts
auth-captureBase SepoliaCDP 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 for x402/clients/mcp/chatbot.ts.
  • ANTHROPIC_MODEL — (MCP chatbot only) override the Claude model. Defaults to claude-sonnet-4-5.
  • X402_API_URL — override the x402-protected URL the HTTP clients call. Defaults to https://x402.vercel.app/protected.
  • X402_FUND_FROM_FAUCET — set to true for one payForApi.ts or payForSchemes.ts run 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.ts only) a CAIP-2 network id (e.g. eip155:84532, solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1) to force on a dual-network route like GET /report, via a registered PaymentPolicy. Omit to let the client pick its default.
  • MCP_SERVER_URL — (MCP clients) the MCP server URL. Defaults to http://localhost:4022.
  • CDP_X402_CLIENT_ENVIRONMENT"production" (default, Base mainnet) or "development" (Base Sepolia). Controls which Base network CdpX402Client prescribes by default; overridden by the environment config option. These examples pass environment: "development" explicitly, so this env var isn't required to run them as-is.
  • CDP_X402_SERVER_ENVIRONMENT — the createX402Server equivalent of the above. The servers also pass environment: "development" explicitly, so this env var isn't required either.
  • Non-Base RPC URLs — pass them via the networkSchemes config option on CdpX402Client, 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 explicit rpcUrl from your own RPC provider.
  • APPROACH — (Express and Hono) which CDP wiring to run: 1, 2 (default), or 3 (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 to 8402 for the HTTP servers and 4022 for the MCP server. Set it per command rather than in .env, where it would move every server.