ByAUJay
Summary: This post shows how your team can ship an x402‑paywalled API in a single weekend—covering middleware you can drop into popular stacks, the exact HTTP headers to speak, how to generate and validate receipts, and the operational guardrails enterprises expect. It’s a concrete, copy‑pasteable guide for decision‑makers who want pay‑per‑call monetization without accounts, OAuth, or a billing backend.
Shipping an x402‑Paywalled API in a Weekend: Middleware, Headers, and Receipts
Decision‑makers tell us they want usage‑based revenue without building a billing team. In late 2025, that’s finally practical with x402: an HTTP‑native payment protocol that “wakes up” 402 Payment Required and lets clients pay for API calls in USDC and other tokens, then retry the same request with a proof. Coinbase stewards the core spec, Cloudflare shipped first‑class support in September 2025, and the ecosystem now includes production facilitators, SDKs, and server middleware across stacks. (coinbase.com)
Below is the fastest path we’ve found to go from “free endpoint” to “revenue per request”—with precise header contracts, base64 payloads, and receipt patterns you can ship this weekend.
Why x402 now (and what changed in 2025)
- HTTP already had 402 Payment Required; the web never standardized how to use it. x402 defines the handshake: server returns 402 with machine‑readable payment requirements; clients pay and retry with an X‑PAYMENT header; servers verify (locally or via a facilitator) and respond 200 with optional settlement details. (developer.mozilla.org)
- Coinbase’s hosted “facilitator” makes this enterprise‑friendly: fee‑free USDC on Base, optional KYT/OFAC checks, SLAs, and REST endpoints to verify and settle. Cloudflare added Workers/Agents integration and co‑launched the x402 Foundation in Sep 2025. (docs.cdp.coinbase.com)
- Tokens and networks: out of the box, USDC via EIP‑3009 “transferWithAuthorization” on EVM, plus Solana support; community/self‑hosted facilitators broaden chain coverage. (docs.cdp.coinbase.com)
Bottom line: you can charge per call without accounts, keys, or PCI scope—and without running blockchain nodes.
The 48‑hour plan
- Friday PM: instrument your API to emit a standards‑compliant 402 with “accepts[]” payment options; stand up middleware.
- Saturday: add X‑PAYMENT validation via a facilitator; return X‑PAYMENT‑RESPONSE receipts; integrate logs/metrics.
- Sunday: pricing policy, idempotency, credit bundles, and production hardening (rate limits, CORS, caching).
We’ll show you exactly what to send and verify at each hop.
Step 1 — Emit a standards‑compliant 402
When a client hits a protected endpoint without proof, respond:
HTTP/1.1 402 Payment Required Content-Type: application/json Cache-Control: no-store X-Request-Id: 7b2a6d3e-7a3f-4b25-86b1-0c19c6f9c2f1 { "x402Version": 1, "error": "payment_required", "accepts": [ { "scheme": "exact", "network": "base", "maxAmountRequired": "1000000", // 1 USDC (6 decimals) "resource": "https://api.example.com/v1/premium/search", "description": "Search 100 docs", "mimeType": "application/json", "payTo": "0x1234...cAFE", "asset": "0xa0b86991c6218b36c1d19d4a2e9eb0cE3606eB48", // USDC (example) "extra": { "eip712": {"name": "USD Coin", "version": "2"}, "validForSeconds": 300 } } ] }
- Required fields: x402Version, accepts[]. Common fields inside a requirement: scheme, network, maxAmountRequired (atomic units), resource. EVM flows typically include payTo, asset (token address), and EIP‑712 metadata for USDC signatures. (github.com)
- Start conservative: one accept option (Base + USDC) and a 5‑minute time window. You can add Solana or additional chains later behind the same endpoint. (docs.cdp.coinbase.com)
Tip: if your endpoint also serves browsers, detect Accept: text/html and show a purchase page while keeping the JSON 402 for programmatic clients. Middleware templates already handle this split. (deepwiki.com)
Step 2 — Let clients pay and retry with X‑PAYMENT
Clients create a signed authorization (gasless in EVM via EIP‑3009) and send it as a base64‑encoded JSON in the X‑PAYMENT header on the retry. For example:
GET /v1/premium/search?q=vector+db HTTP/1.1 Host: api.example.com X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoiYmFzZSIsInBheWxvYWQiOnsiYXV0aG9yaXphdGlvbiI6eyJmcm9tIjoiMHhQQVlFUiIsInRvIjoiMHhQQVlFRSIsInZhbHVlIjoiMTAwMDAwIiwidmFsaWRBZnRlciI6IjE3NDg3NjI4MDQiLCJ2YWxpZEJlZm9yZSI6IjE3NDg3NjMxMDQiLCJub25jZSI6IjB4YWJjLi4uIn0sInNpZ25hdHVyZSI6IjB4NTU1Li4uIn19fQ==
What’s inside after base64:
{ "x402Version": 1, "scheme": "exact", "network": "base", "payload": { "authorization": { "from": "0xPAYER", "to": "0xPAYEE", "value": "1000000", "validAfter": "1748762804", "validBefore": "1748763104", "nonce": "0x…32 bytes…" }, "signature": "0x…EIP-712 signature…" } }
- Header name and encoding: X‑PAYMENT, base64‑encoded JSON; EVM payloads use EIP‑3009 TransferWithAuthorization for USDC (no native gas needed—the facilitator submits). (github.com)
- Many SDKs generate this for you: e.g., thirdweb’s wrapFetchWithPayment, Coinbase’s fetchWithX402, or Cloudflare’s x402‑fetch for Workers/Agents. (portal.thirdweb.com)
Step 3 — Verify and settle (server or facilitator)
On your server, when X‑PAYMENT is present:
- Parse and sanity‑check against your requirement (resource, network, maxAmountRequired).
- Verify authorization and settle:
- Local: call the token’s transferWithAuthorization (EIP‑3009) or the Solana transfer, then wait for confirmation.
- Facilitator: POST the header + your requirement to /verify and /settle, then await the response. (docs.cdp.coinbase.com)
Coinbase facilitator endpoints:
- POST /v2/x402/verify — validate the payload against the requirement.
- POST /v2/x402/settle — submit the onchain transfer and return a settlement result (tx hash, network, payer, amount). (docs.cdp.coinbase.com)
Why we recommend a facilitator for weekend shipping:
- You avoid managing blockchain connectivity, gas, and reorgs.
- CDP’s facilitator on Base is fee‑free for USDC and includes optional compliance checks. (docs.cdp.coinbase.com)
Step 4 — Return a receipt via X‑PAYMENT‑RESPONSE
After successful verification/settlement, include a machine‑readable receipt header:
HTTP/1.1 200 OK Content-Type: application/json Access-Control-Expose-Headers: X-PAYMENT-RESPONSE X-PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IjB4OGYzZC4uLiIsIm5ldHdvcmsiOiJiYXNlIiwicGF5ZXIiOiIweFBBWUVSIiwicmVzb3VyY2UiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbS92MS9wcmVtaXVtL3NlYXJjaCIsImFtb3VudCI6IjEwMDAwMCIsInNldHRsZWRBdCI6MTc0ODc2MzEwOS4xOTV9
Decoded:
{ "success": true, "transaction": "0x8f3d…", "network": "base", "payer": "0xPAYER", "resource": "https://api.example.com/v1/premium/search", "amount": "1000000", "settledAt": 1748763109.195 }
The header name and base64 JSON pattern are part of the x402 spec; exposing it via CORS lets browser clients inspect proofs. (github.com)
If you offer multi‑credit purchases (buy 5 calls at once), return an X‑PAYMENT “token” value in the response as a reusable credit; subsequent calls can present that same token until credits are exhausted. (docs.proxy402.com)
Drop‑in middleware for popular stacks
We recommend starting with framework packages rather than writing the protocol by hand.
- Node/Express: x402‑express or a thin custom middleware that:
- If no X‑PAYMENT, returns the 402 JSON above.
- If X‑PAYMENT, posts header+requirement to your facilitator, handles result, and sets X‑PAYMENT‑RESPONSE. (deepwiki.com)
- Cloudflare Workers (Hono): use x402‑hono + x402‑fetch to both protect routes and call paywalled upstreams from agents. (developers.cloudflare.com)
- Client: thirdweb wrapFetchWithPayment, or Coinbase’s fetchWithX402 (React hooks or vanilla), which automatically detect 402, build a payment payload, and retry. (portal.thirdweb.com)
A minimalist Express‑style server guard:
// pseudo‑impl: use official packages in production app.use("/v1/premium/search", async (req, res, next) => { const requirement = mkRequirement({ maxCents: 100 }); // 1 USDC const header = req.get("X-PAYMENT"); if (!header) return res.status(402).json(mk402(requirement)); const verify = await fetch(FACILITATOR + "/v2/x402/verify", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ paymentHeader: header, requirement }) }).then(r => r.json()); if (!verify.valid) { return res.status(402).json(mk402(requirement, verify.error)); } const settle = await fetch(FACILITATOR + "/v2/x402/settle", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ paymentHeader: header, requirement }) }).then(r => r.json()); res.set("Access-Control-Expose-Headers", "X-PAYMENT-RESPONSE"); res.set("X-PAYMENT-RESPONSE", b64(settle)); return next(); // continue to handler that returns the actual resource });
Pricing and SKUs that work in practice
- Start with a single “exact” price per call (e.g., $0.01) and represent it as 1,000,000 atomic units (USDC has 6 decimals). Document that clients must never exceed maxAmountRequired. (github.com)
- Bundle credits: offer 5‑ or 20‑call bundles with a response token clients can reuse until credit=0; keep the token lifetime bounded to reduce risk. (docs.proxy402.com)
- Dynamic pricing: your middleware can compute maxAmountRequired per request (e.g., per model/token count) but must bind payment to the specific resource URL to prevent replay across different APIs. (github.com)
Receipts your finance and security teams will accept
Return at least three proof layers:
- On‑chain proof (transaction hash + network) via X‑PAYMENT‑RESPONSE.
- Request binding (resource URL and X‑Request‑Id) in the same receipt object.
- Server‑signed service receipt (optional): sign a compact receipt hash with your server key for immutable audit trails.
For multi‑party workflows (agents calling suppliers), consider emerging “verifiable delivery” receipts that tie “what was delivered” to “what was paid.” Projects are combining x402 payments with cryptographic delivery attestations so buyers can prove the response matched a declared policy. (build.avax.network)
Retention policy: store the decoded receipt JSON and raw headers for 7–90 days depending on your audit requirements; index by tx hash and request id.
Security and fraud controls you can implement in hours
- Enforce tight validity windows: verify validAfter/validBefore on the EIP‑3009 authorization and reject stale authorizations. (docs.icpay.org)
- Idempotency: hash (payer, resource, value, nonce) and reject duplicates to prevent double‑spend attempts on the same call.
- Compliance: route all verifications through a facilitator that screens KYT/OFAC for enterprise policies. (docs.cdp.coinbase.com)
- CORS and header exposure: set Access‑Control‑Expose‑Headers: X‑PAYMENT‑RESPONSE so browsers can read receipts. (build.avax.network)
- CDN behavior: cache‑bust 402s (Cache‑Control: no‑store) and mark 200s public/private per data sensitivity; do not cache X‑PAYMENT‑RESPONSE itself.
- Replay isolation: include resource in both requirement and receipt; verify the retry uses the exact same method+path+query used to generate the 402. (github.com)
Observability: the dashboards you’ll want on Monday
Log these fields on both 402 and 200:
- request_id, method, path, canonical_query
- payer, network, amount_atomic
- facilitator: name/version, verify_ms, settle_ms
- tx_hash, settled_at, success
- sku, credits_remaining (if applicable)
Export to your SIEM and BI; alert on verify/settle failure rates and on “verify valid but settle failed” spikes (often gas conditions if self‑settling).
Production choices: facilitator vs. self‑hosted vs. hybrid
- Hosted (CDP): fastest time‑to‑value, enterprise compliance, Base + Solana, fee‑free USDC on Base. Great default for pilots and enterprise rollouts. (docs.cdp.coinbase.com)
- Community/self‑hosted: add EVMs/Solana variants or custom tokens; keep control of latency and routing. Ensure your facilitator implements /supported discovery, verify, and settle endpoints. (deepwiki.com)
- Client SDK landscape: thirdweb supports 170+ EVMs (permit or 3009), Coinbase hooks for embedded wallets, Workers/Agents wrappers for Cloudflare. (portal.thirdweb.com)
L402 vs. x402 (and when each fits)
Lightning Labs’ L402 (formerly LSAT) pioneered 402‑style API monetization using Macaroons and the Lightning Network. If you already run Lightning infra and like Macaroon caveats, it’s a strong fit. x402 targets EVM/Solana, USDC‑first, HTTP‑header payloads, and facilitator patterns that minimize blockchain complexity for web backends. Some teams run both: L402 for BTC/Lightning users, x402 for stablecoin flows to Base/Solana. (github.com)
Edge and agents: why this matters to AI roadmaps
Cloudflare Workers/Agents and MCP stacks now wrap fetch with x402 so agents can autonomously buy data, tools, and model inferences with provable receipts. That removes “bring‑your‑own‑API‑key” friction and lets you meter per‑call at the edge. (developers.cloudflare.com)
Common pitfalls (we keep seeing) and exact fixes
- Atomic vs. decimal mismatch: always compute USDC in 6‑decimals atomic units server‑side; never trust client decimals. Bind maxAmountRequired in atomic form. (github.com)
- Wrong chain identifiers: use canonical network strings (e.g., "base", "base‑sepolia", "solana"). Validate before Verification. (docs.cdp.coinbase.com)
- Missing header exposure: without Access‑Control‑Expose‑Headers, browser clients cannot read X‑PAYMENT‑RESPONSE—leads to brittle UIs. (build.avax.network)
- Over‑caching 402s: add Cache‑Control: no‑store on 402; otherwise CDNs can “stick” the paywall even after payment.
- Long validity windows: keep ≤5 minutes; rotate nonces; include resource in the signed scope to prevent cross‑endpoint replay. (docs.icpay.org)
A concrete weekend checklist
Friday (3–5 hours)
- Pick facilitator (CDP for Base mainnet; community for Base Sepolia dev). Get API keys if using CDP. (docs.cdp.coinbase.com)
- Wrap protected routes with middleware that returns the 402 JSON above; unit‑test accepts[]. (github.com)
Saturday (4–6 hours)
- Add handler for X‑PAYMENT:
- post to /verify, then /settle; handle failure modes (invalid signature, expired, underpay). (docs.cdp.coinbase.com)
- Return X‑PAYMENT‑RESPONSE with tx hash and resource; expose header via CORS. (build.avax.network)
- Wire metrics and structured logs.
Sunday (3–5 hours)
- Pricing policy: flat + bundles; document SKUs and credit lifetimes. (docs.proxy402.com)
- Hardening: rate limits, no‑store on 402, bounded time windows, idempotency keys, graceful fallback to 402 on facilitator errors.
- Smoke tests with thirdweb wrapFetchWithPayment and a browser client; test in Base Sepolia, then flip to Base mainnet. (portal.thirdweb.com)
Server and client snippets you can adapt
Protecting a FastAPI endpoint (sketch):
from fastapi import FastAPI, Request, Response import httpx, base64, json, os app = FastAPI() FAC = os.getenv("X402_FACILITATOR") # e.g., https://api.cdp.coinbase.com def mk_req(): return { "x402Version": 1, "accepts": [{ "scheme": "exact", "network": "base", "maxAmountRequired": "1000000", "resource": "https://api.example.com/v1/premium/search", "payTo": "0x1234...cAFE", "asset": "0xA0b8...6eB48", "extra": {"eip712": {"name":"USD Coin","version":"2"}} }] } @app.get("/v1/premium/search") async def premium_search(req: Request): xpay = req.headers.get("x-payment") if not xpay: return Response(json.dumps(mk_req()), 402, media_type="application/json") payload = {"paymentHeader": xpay, "requirement": mk_req()["accepts"][0]} async with httpx.AsyncClient() as c: v = (await c.post(f"{FAC}/v2/x402/verify", json=payload)).json() if not v.get("valid", False): return Response(json.dumps(mk_req() | {"error": v.get("error","invalid_payment")}), 402) s = (await c.post(f"{FAC}/v2/x402/settle", json=payload)).json() res = Response(json.dumps({"result": "ok", "items": []}), media_type="application/json") res.headers["Access-Control-Expose-Headers"] = "X-PAYMENT-RESPONSE" res.headers["X-PAYMENT-RESPONSE"] = base64.b64encode(json.dumps(s).encode()).decode() return res
Client (browser) using thirdweb’s x402 wrapper:
import { wrapFetchWithPayment } from "thirdweb/x402"; import { createThirdwebClient } from "thirdweb"; import { inAppWallet } from "thirdweb/wallets"; const client = createThirdwebClient({ clientId: process.env.THIRDWEB_ID! }); const wallet = inAppWallet(); const paidFetch = wrapFetchWithPayment({ client, wallet }); const r = await paidFetch("https://api.example.com/v1/premium/search?q=vector+db"); const receipt = atob(r.headers.get("X-PAYMENT-RESPONSE")!); // use receipt in your audit log UI
Both snippets rely on the standard 402 → X‑PAYMENT → X‑PAYMENT‑RESPONSE dance defined by x402. (portal.thirdweb.com)
Enterprise answers to common objections
- “Do we need wallets?” Your users don’t need to manage keys; embed wallets or rely on agent wallets. Facilitators sponsor gas for EIP‑3009 flows; buyers only sign authorizations. (docs.cdp.coinbase.com)
- “Which networks and tokens are truly supported?” Today: Base mainnet (USDC, fee‑free via CDP), Base Sepolia for testing, plus Solana (via facilitators). Self‑hosted/community facilitators can add more EVMs. (docs.cdp.coinbase.com)
- “Is this only for crypto‑native teams?” No—Workers/Agents and React hooks hide the crypto; your team speaks HTTP and headers. (developers.cloudflare.com)
Final notes before you ship
- Be explicit with decimals (atomic units), chains, and 5‑minute validity windows.
- Always bind payment to the resource URL and method; log the request id into the receipt object.
- Start with a single facilitator and one token (USDC on Base), measure conversion, then expand.
x402 has matured rapidly—standard headers, hosted facilitators, and edge‑native wrappers mean you can add metered revenue to existing APIs without re‑architecting authentication. If you want help instrumenting 402s, tuning pricing, or designing verifiable receipts and dashboards, 7Block Labs ships this in days, not quarters.
References and further reading
- Coinbase x402 (spec, headers, facilitator APIs, how it works). (github.com)
- Network and token support (USDC via EIP‑3009, Base/Solana, facilitator models). (docs.cdp.coinbase.com)
- Cloudflare + Coinbase partnership and Workers/Agents integration (Sep 23, 2025). (blog.cloudflare.com)
- HTTP 402 background (MDN). (developer.mozilla.org)
- X‑PAYMENT and X‑PAYMENT‑RESPONSE header patterns; credit token examples. (build.avax.network)
- L402 (Lightning) for context. (github.com)
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

