{"slug": "charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify", "title": "Charge per API call in USDC — and give buyers a receipt they can verify", "summary": "A developer built an Express endpoint that charges per API call in USDC via the x402 protocol and provides a signed receipt (EIP-712 attestation) that buyers can verify before acting on the response. The implementation uses the MIT-licensed @foreseal/gate and @payperbyte/sdk libraries to ensure data integrity, rejecting tampered or spoofed responses.", "body_md": "AI agents can now pay for things on their own. The [x402 protocol](https://x402.org) reuses HTTP `402 Payment Required`\n\nso a client — human or agent — pays per API call in USDC, no API keys, no accounts, no subscription. It's a genuinely nice primitive.\n\nBut there's a gap that bites the moment an agent acts on what it paid for: **the payment rail proves the money moved. It says nothing about the bytes that came back.** An agent can pay perfectly and still act on tampered or spoofed data.\n\nSo here's what I wired up, and how you can too: an Express endpoint that charges per call in USDC **and** hands the buyer a signed receipt they can verify *before* acting on the response. The packages underneath are free and MIT — this is just the assembly, shown plainly.\n\n```\nclient ──GET /price──▶  402 Payment Required  (USDC terms)\nclient ──pay USDC───▶  200 OK + your data + an X-BYTE-Attestation receipt\nclient ──verify────▶  recompute hash, recover signer → act or refuse\n```\n\nTwo small libraries do the work:\n\n`@foreseal/gate`\n\n`@payperbyte/sdk`\n\nBoth MIT. You can absolutely wire them yourself; that's the point of this post.\n\n``` python\nimport express from \"express\";\nimport { trustMiddleware } from \"@foreseal/gate\";\n\nconst app = express();\napp.use(express.json());\n\napp.use(\n  \"/price\",\n  trustMiddleware({\n    upstream: \"https://your-api.example.com/data\", // your real endpoint\n    price: { perCallUsdc: \"0.01\" },                // or { perKBUsdc, floorUsdc }\n    payTo: \"0xYourUSDCAddressOnBase\",              // where USDC settles\n    attestation: \"delivery\",                        // stamp every paid 200\n  }),\n);\n\napp.listen(3000);\n```\n\nThat's the whole integration. An unpaid call gets a `402`\n\nwith x402 USDC terms. On payment, the gate proxies your upstream and stamps the response with an **EIP-712 attestation over the exact bytes it served** — byte for byte — in an `X-BYTE-Attestation`\n\nheader.\n\n```\ncurl -i http://localhost:3000/price\n# HTTP/1.1 402 Payment Required\n# ... x402 payment terms (asset, amount, network, payTo) ...\n```\n\nThe client pays in USDC, retries with the payment header, and gets `200`\n\nplus the data and the receipt. Standard x402 flow — the gate just adds the receipt.\n\nThis is the half everyone skips. Before your code (or your agent) acts on the response, recompute the hash of the exact bytes and recover the signer. If either is wrong, refuse.\n\n``` js\nimport { verifyFromGatewayResponse, ARBITRUM_SEPOLIA } from \"@payperbyte/sdk\";\n\nconst res    = await fetch(url, { headers: paymentHeaders }); // your paid call\nconst body   = await res.text();                              // the EXACT bytes\nconst header = res.headers.get(\"x-byte-attestation\");\n\nconst v = await verifyFromGatewayResponse(\n  body, header, ARBITRUM_SEPOLIA, gatewayAttester, // pin the seller's attester\n);\nif (!v.verified) throw new Error(\"refuse: \" + v.reason);\n// ...safe to act on `body`.\n```\n\nYou can prove the mechanic offline, no wallet and no network — sign a sample receipt, then verify it and two attacks:\n\n```\nverify-before-act:\n  genuine        → verified=true    received bytes match the attested hash AND signer — safe to act\n  tampered byte  → verified=false   HASH MISMATCH — do not act\n  forged signer  → verified=false   bad recover — do not act\n```\n\nAccept genuine. Refuse tampered and forged. That's the gate.\n\nThis is important enough to say out loud, because plenty of \"verified data\" pitches blur it:\n\nSo the claim is narrow and useful: *\"these are genuinely the bytes the seller signed,\"* not *\"this number is right.\"* You still decide whether to trust the seller. The receipt just removes the question of whether you got their actual bytes. Tell your own users which one you mean.\n\nThe EIP-712 signing domain is anchored at ** chainId 421614 (Arbitrum Sepolia)** — a\n\n`ARBITRUM_SEPOLIA`\n\nto the verifier even though the money moved on Base. Recovery happens in the domain; settlement happens on the rail. Mix them up and your signatures won't recover — budget five minutes of confusion here, then never again.Default to ** base-sepolia**: the public x402 facilitator advertises testnet, so the full\n\n`402 → pay → 200 → receipt`\n\nloop works for free with testnet USDC, no keys. (On Base mainnet For real USDC on Base mainnet, point at the Coinbase CDP facilitator:\n\n```\nNETWORK=base\nFACILITATOR_AUTH=cdp\nCDP_API_KEY_ID=...\nCDP_API_KEY_SECRET=...\n# and: npm i @coinbase/x402\n```\n\nI ran this end-to-end on Base mainnet — the `402`\n\nadvertises `network: eip155:8453`\n\n, the canonical Base USDC asset, and your `payTo`\n\n. Develop on testnet, flip one env block for mainnet. That's the only change.\n\nNo install, no wallet — see the whole accept-genuine / refuse-tampered loop locally:\n\n```\nnpx @foreseal/demo\n```\n\nIt runs offline and shows an agent **act** on genuine bytes and **refuse** a tampered byte, a forged signature, a missing receipt, and a forked signing domain — in about a second.\n\n`byte-mcp-server`\n\n`buy → verify-before-act`\n\ntool out of the box.Either way: if your code acts on data it paid for, verify it first. Provenance is cheap. Acting on tampered bytes isn't.\n\n*Questions or corrections welcome in the comments — I'd rather fix something than leave it wrong.*", "url": "https://wpnews.pro/news/charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify", "canonical_source": "https://dev.to/0rkz/charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify-59nc", "published_at": "2026-06-29 20:23:54+00:00", "updated_at": "2026-06-29 20:48:44.007028+00:00", "lang": "en", "topics": ["developer-tools", "artificial-intelligence", "ai-agents"], "entities": ["x402", "USDC", "EIP-712", "Arbitrum Sepolia", "Base", "Express", "@foreseal/gate", "@payperbyte/sdk"], "alternates": {"html": "https://wpnews.pro/news/charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify", "markdown": "https://wpnews.pro/news/charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify.md", "text": "https://wpnews.pro/news/charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify.txt", "jsonld": "https://wpnews.pro/news/charge-per-api-call-in-usdc-and-give-buyers-a-receipt-they-can-verify.jsonld"}}