ByAUJay
Creating API for Web3 with x402: Paywalled Endpoints and Receipt Verification
x402 turns the long‑ignored HTTP 402 “Payment Required” into a production‑grade payment rail for APIs. In this guide, we show decision‑makers and engineering leads how to stand up pay‑per‑request endpoints and ship cryptographically verifiable receipts that your auditors, partners, and autonomous agents can trust.
Summary: Monetize any HTTP endpoint with per‑request USDC payments via x402, then return a verifiable receipt alongside 200 OK. This article covers the minimal server changes, client flow, facilitator choices, and emerging best practices your team can adopt today.
Why x402 now (and why it matters for APIs)
- HTTP‑native payments: x402 adds payments to the exact place your API already talks—HTTP request/response—without OAuth, API keys, or account onboarding. The server replies 402 with payment terms; the client retries with a signed payment in a single header. (docs.cdp.coinbase.com)
- Enterprise‑ready facilitator: Coinbase’s hosted facilitator verifies/settles fee‑free USDC on Base mainnet and brings KYT/OFAC screening and reporting—critical for regulated teams. (docs.cdp.coinbase.com)
- Proven spec and SDKs: The open x402 spec defines the 402 payload, the X‑PAYMENT request header, and the X‑PAYMENT‑RESPONSE settlement header, with reference clients/servers in multiple languages. (github.com)
Bottom line: you can turn “paid API” from a billing project into one line of middleware plus a few integration points your team already understands. (github.com)
What you’ll build
- Paywalled endpoints that:
- Return HTTP 402 with live payment requirements when called without payment.
- Accept a retry with an X‑PAYMENT header (a signed, base64 JSON payload).
- Verify and settle via a facilitator, then return 200 OK with an X‑PAYMENT‑RESPONSE header containing transaction details.
- Verifiable receipts your customers and agents can check offline:
- Baseline: use X‑PAYMENT‑RESPONSE to communicate chain, tx hash, and payer.
- Advanced: add a JWS receipt header (e.g., PEAC‑Receipt) signed by your service, binding policy and content hash for non‑repudiation. (docs.cdp.coinbase.com)
The x402 request–payment–response flow, precisely
-
Client requests a protected resource:
GET /v1/insights?id=abc -
Server replies with 402 Payment Required and a JSON body describing accepted payment methods (you can list multiple networks/tokens):
{ "x402Version": 1, "accepts": [ { "scheme": "exact", "network": "base-mainnet", "maxAmountRequired": "10000", "resource": "https://api.example.com/v1/insights?id=abc", "description": "Research insight: abc", "mimeType": "application/json", "payTo": "0xYourPayableAddress", "asset": "0xUSDCContractOnBase", "maxTimeoutSeconds": 10, "extra": { "eip712": { "name": "USD Coin", "version": "2" } } } ] }
- Key fields align to the x402 spec: scheme/network, amount, payTo, asset, timeout, and optional EIP‑712 metadata for EVM tokens. Use one “accepts” entry per supported network/token. (github.com)
- The client constructs X‑PAYMENT:
- For EVM “exact” scheme, the client builds an EIP‑712 signature for an EIP‑3009 TransferWithAuthorization payload (from, to, value, validAfter, validBefore, nonce). This allows gasless settlement via a relayer/facilitator. (eips.ethereum.org)
-
Client retries with X‑PAYMENT header:
GET /v1/insights?id=abc
X‑PAYMENT: <base64( { x402Version, scheme, network, payload } )> -
Server verifies and settles through a facilitator (/verify then /settle). If valid, it executes the request and returns:
HTTP/1.1 200 OK
X‑PAYMENT‑RESPONSE: <base64( { success, txHash, networkId, payer } )> (docs.cdp.coinbase.com)
Architecture choices that de‑risk go‑live
- Facilitator options, as of December 2025:
- CDP‑hosted: Production‑ready; Base and Solana (plus testnets); USDC default; fee‑free settlement on Base; requires CDP keys. Best for enterprises needing compliance/KYT. (docs.cdp.coinbase.com)
- Community or self‑hosted: For dev/test or custom chains; implement the same /verify and /settle interfaces. Track public facilitators on x402scan. (docs.cdp.coinbase.com)
- Token support:
- USDC is default across networks. Custom ERC‑20s must implement EIP‑3009; Solana supports SPL tokens without EIP‑712 steps. (docs.cdp.coinbase.com)
Decision tip: Start with CDP‑hosted on Base + USDC for the shortest path to revenue and audit‑friendly reporting; expand to other chains/tokens via self‑hosted facilitators once volume justifies. (docs.cdp.coinbase.com)
Server blueprint: add a 402 paywall in one afternoon
Below is a minimal Express implementation pattern your team can adapt (conceptual code; log/metrics omitted for clarity).
- Declare pricing and assets per route:
// price: $0.01 per call, settled in USDC on Base const pricing = { "/v1/insights": { usd: "0.01", network: "base-mainnet", asset: process.env.USDC, payTo: process.env.PAYOUT } };
- Middleware to enforce 402 and verify payment:
import { verifyWithFacilitator, settleWithFacilitator } from "./x402-facilitator"; app.use("/v1/insights", async (req, res, next) => { const price = pricing["/v1/insights"]; const hasPayment = typeof req.headers["x-payment"] === "string"; if (!hasPayment) { // Respond 402 with Payment Requirements return res.status(402).json({ x402Version: 1, accepts: [{ scheme: "exact", network: price.network, maxAmountRequired: dollarsToAtomic(price.usd), resource: absoluteUrl(req), description: "Insight retrieval", mimeType: "application/json", payTo: price.payTo, asset: price.asset, maxTimeoutSeconds: 10, extra: { eip712: { name: "USD Coin", version: "2" } } }] }); } // Verify payment header with facilitator const paymentHeader = String(req.headers["x-payment"]); const verify = await verifyWithFacilitator({ x402Version: 1, paymentHeader, paymentRequirements: /* same object as above */ }); if (!verify.isValid) { return res.status(402).json({ x402Version: 1, accepts: [/* ... */], error: "Invalid payment" }); } // Execute business logic const data = await fetchInsight(req.query.id as string); // Settle and attach receipt const settle = await settleWithFacilitator({ x402Version: 1, paymentHeader, paymentRequirements: /* ... */ }); res.setHeader("X-PAYMENT-RESPONSE", encodeBase64({ success: settle.success, txHash: settle.txHash, networkId: settle.networkId, payer: extractPayer(paymentHeader) })); return res.status(200).json(data); });
- The verify/settle RPCs and headers follow the x402 spec; use Coinbase’s facilitator for production to avoid running nodes or writing chain‑specific code. (github.com)
- Operational knobs to set on day one
- maxTimeoutSeconds: Cap how long you’ll wait for settlement before responding; prefer 5–15s for most APIs. (github.com)
- Per‑route pricing: Keep pricing server‑side and compute atomic units on demand to avoid drift.
- Idempotency: Accept a custom X‑Idempotency‑Key to ensure safe retries around network hiccups.
Client blueprint: handle 402 automatically
Your client (human app or AI agent) should transparently convert 402 into a payment and retry:
import { buildEIP3009Auth, signTypedData, wrapFetch } from "./client-x402"; // A fetch wrapper that auto-pays once, then retries async function fetchWithPayment(url: string, opts: any = {}) { const res = await fetch(url, opts); if (res.status !== 402) return res; const body = await res.json(); const accept = body.accepts[0]; // choose best option for your wallet/network const auth = buildEIP3009Auth({ from: wallet.address, to: accept.payTo, value: accept.maxAmountRequired, validBefore: nowPlus(60), validAfter: nowMinus(5), nonce: randomBytes32() }, accept.extra.eip712); const signature = await signTypedData(wallet, auth.typedData); const paymentHeader = base64JSON({ x402Version: 1, scheme: accept.scheme, network: accept.network, payload: { authorization: auth.authorization, signature } }); // Retry with X-PAYMENT return fetch(url, { ...opts, headers: { ...(opts.headers || {}), "X-PAYMENT": paymentHeader } }); }
- EVM “exact” uses EIP‑3009 so the user signs only once; your facilitator pays gas and settles on‑chain. This is ideal for tiny per‑request charges. (eips.ethereum.org)
Tip: If your client is an agent, wire in a spending policy (max per request/day) and fall back to free cache when policy triggers.
Receipt verification: from “tx hash included” to “non‑repudiation”
You have two complementary layers of proof.
- On‑chain settlement details in X‑PAYMENT‑RESPONSE
- Always include transaction hash, network, and (if available) payer. Clients can verify settlement on a block explorer or through their own RPC and tie it to the exact HTTP response. (docs.cdp.coinbase.com)
- Cryptographic receipt header (advanced)
- Emit a signed JWS receipt (e.g., PEAC‑Receipt) along with 200 OK. Include fields such as issuer (your API), subject (the caller or agent ID), resource URL, policy/version, the exact amount, settlement tx hash, and optionally a content hash of the response body. Verify with your public key published at /.well‑known/peac.txt. (x402.peacprotocol.org)
Example structure your team can adopt:
{ "iss": "https://api.example.com", "sub": "did:key:z6Mk...", "resource": "https://api.example.com/v1/insights?id=abc", "policy": "pricing:v3 / terms:2025-10-01", "paid": { "amount": "0.01", "currency": "USD", "scheme": "x402", "network": "base-mainnet" }, "settlement": { "txHash": "0x...", "asset": "USDC", "to": "0xYourPayableAddress" }, "bodyHash": "sha256-BASE64==", "iat": 1733611200, "exp": 1733611800 }
- Why add JWS receipts? Auditors can prove exactly what was purchased, by whom, when, and under which policy—even if your API or the facilitator is offline later. PEAC documents an end‑to‑end pattern, including agent discovery and policy publishing. (x402.peacprotocol.org)
Security model and anti‑fraud controls that actually work
- Replay protection: EIP‑3009 uses a random nonce and a validity window (validAfter/validBefore). Always enforce both server‑side when verifying. (eips.ethereum.org)
- Recipient binding: Prefer receiveWithAuthorization semantics when settling from a contract context to prevent front‑running; many facilitators enforce payTo matching. (eips.ethereum.org)
- Pricing integrity: Do not trust client‑provided amounts—compute required atomic units (e.g., USDC 6 decimals) server‑side to match your current USD price string and include only the maximum in 402 to prevent underpayment. (docs.cdp.coinbase.com)
- Policy versioning: Include policy/version identifiers in both your 402 body and your receipt; rotate keys and publish your current receipt signing key in a .well‑known location. (x402.peacprotocol.org)
- Compliance: If you need sanctions screening and enterprise support, run through the CDP facilitator for KYT/OFAC checks. Self‑hosted facilitators won’t give you that out of the box. (coinbase.com)
Choosing networks and tokens
- Start on Base with USDC for lowest friction and enterprise features; expand to Solana for SPL tokens if your users are there; add custom EIP‑3009 tokens when you control both sides of the market. (docs.cdp.coinbase.com)
- If your product mix requires ERC‑2612 tokens or many EVM chains, consider a client stack that can build X‑PAYMENT from either EIP‑3009 or ERC‑2612 permits (several SDKs support both). Treat ERC‑2612 as an optimization for tokens that lack 3009. (portal.thirdweb.com)
Testing and observability
- Sandbox first: Community facilitators default to testnets; flip to CDP‑hosted for mainnet readiness with SLA. (docs.cdp.coinbase.com)
- Metrics worth shipping from day one:
- 402→200 conversion rate and median time‑to‑settlement.
- Top 10 endpoints by revenue and payer cohort (human vs agent).
- 402 error breakdown: invalid signature, expired authorization, insufficient balance.
- Logs: Store decoded X‑PAYMENT (minus signature) and the decoded X‑PAYMENT‑RESPONSE for audit replay; hash response bodies and include the hash in your receipt to bind payment to content.
- Post‑settlement webhooks: If your product triggers downstream jobs, use the facilitator’s settle response as the single source of truth for “paid.”
Refunds, disputes, and chargebacks
- No chargebacks: on‑chain settlement eliminates card‑network disputes; you implement business‑logic refunds by sending a new on‑chain transfer to the payer when warranted. Document refund policies in your receipt policy string and sign them into the JWS receipt. (coinbase.com)
- Partial refunds: For metered work that finishes under budget, you can:
- Switch to an “upto” scheme as it becomes available (pay up to a cap), or
- Return a rebate transfer in a second transaction, referencing the original receipt ID.
Production checklist (enterprise edition)
- Governance
- Key management for receipt signing (HSM or cloud KMS).
- Policy versioning and retention strategy for receipts.
- Compliance
- Use CDP facilitator for KYT/OFAC; verify your org’s reporting needs are covered by its dashboards. (coinbase.com)
- Engineering
- Timeouts: 10s default; serve a 202 Accepted with webhook callback for long jobs.
- Idempotency: Require X‑Idempotency‑Key for all POSTs that trigger chargeable work.
- Rate limits: Price tiers and caps by API path; add free tier endpoints to avoid agent stampedes.
- Risk
- Fraud controls: Soft‑fail rules for new wallets, velocity caps, deny‑lists aligned to KYT signals.
- Kill switch: Rapidly disable paywalls or switch facilitator endpoints via config.
Worked example: monetizing an insights endpoint
Goal: Charge $0.01 per insight on Base in USDC with verifiable receipts.
- Configure route:
paymentConfig["/v1/insights"] = { priceUsd: "0.01", network: "base-mainnet", asset: env.USDC_BASE, payTo: env.TREASURY };
- 402 response builder:
function buildRequirements(req) { const c = paymentConfig["/v1/insights"]; return { x402Version: 1, accepts: [{ scheme: "exact", network: c.network, maxAmountRequired: dollarsToAtomic(c.priceUsd, 6), resource: absoluteUrl(req), description: "Insight", mimeType: "application/json", payTo: c.payTo, asset: c.asset, maxTimeoutSeconds: 10, extra: { eip712: { name: "USD Coin", version: "2" } } }] }; }
- Verify + settle:
// POST /verify and /settle per x402 facilitator interface const verify = await http.post(FACILITATOR + "/verify", { x402Version: 1, paymentHeader, paymentRequirements: reqs.accepts[0] }); if (!verify.isValid) return res.status(402).json({ ...reqs, error: "invalid_payment" }); const [data, settle] = await Promise.all([ fetchInsight(req.query.id as string), http.post(FACILITATOR + "/settle", { x402Version: 1, paymentHeader, paymentRequirements: reqs.accepts[0] }) ]); res.setHeader("X-PAYMENT-RESPONSE", base64JSON({ success: settle.success, txHash: settle.txHash, networkId: settle.networkId, payer: extractPayer(paymentHeader) })); return res.status(200).json(data);
- Add a JWS receipt:
const receipt = signJWS({ iss: "https://api.example.com", sub: req.headers["x-wallet-did"], resource: absoluteUrl(req), policy: "pricing:v1;terms:2025-12-01", paid: { amount: "0.01", currency: "USD", scheme: "x402", network: "base-mainnet" }, settlement: { txHash: settle.txHash, asset: "USDC", to: c.payTo }, bodyHash: sha256Base64(JSON.stringify(data)), iat: now(), exp: now() + 300 }, RECEIPT_SIGNING_KEY); res.setHeader("PEAC-Receipt", receipt);
- This combines the baseline x402 settlement header with an app‑signed JWS for offline verification. The PEAC pattern specifies discovery and verification details you can adopt as‑is. (x402.peacprotocol.org)
Emerging best practices we recommend to clients
- Dual receipts: Always include X‑PAYMENT‑RESPONSE; add a JWS receipt for long‑term auditability and policy binding. (docs.cdp.coinbase.com)
- Publish /.well‑known/peac.txt with your receipt public keys and policy URLs so agents can self‑serve verification. (x402.peacprotocol.org)
- Price in USD, settle in USDC: Keep business logic in fiat terms while avoiding FX slippage on chain. USDC is first‑class in x402 facilitators. (docs.cdp.coinbase.com)
- Prefer “exact” for fixed‑price endpoints; move to “upto” schemes for metered AI inferences when standardized. (github.com)
- Start on Base with CDP‑hosted facilitator for compliance and support; add Solana/SPL as your audience demands. (docs.cdp.coinbase.com)
- Use EIP‑3009 today; layer in ERC‑2612 support on clients to broaden token coverage where needed. (eips.ethereum.org)
What’s next
- Ship your first paid endpoint in a dev environment using the community facilitator, then flip to CDP‑hosted for mainnet and dashboards. (docs.cdp.coinbase.com)
- Add receipts and publish discovery metadata so agents can trust but verify. (x402.peacprotocol.org)
- Roll out pricing experiments route‑by‑route; x402 lets you edit business terms without changing auth or account flows.
If you need a partner to design the policy model, build the facilitator glue, or wire in enterprise observability and compliance, 7Block Labs can help you prove revenue in weeks—not quarters.
References and further reading:
- Coinbase x402: protocol flow, headers, and facilitator model. (docs.cdp.coinbase.com)
- Network/token support and CDP‑hosted capabilities. (docs.cdp.coinbase.com)
- Product overview (KYT/OFAC, dashboards). (coinbase.com)
- EIP‑3009 (TransferWithAuthorization), the foundation for gasless EVM “exact” payments. (eips.ethereum.org)
- PEAC receipts and /.well‑known discovery for verifiable paid calls. (x402.peacprotocol.org)
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

