{"slug": "we-gave-our-api-a-cash-register-then-we-asked-an-ai-to-rob-it-x402-gateway-on", "title": "We Gave Our API a Cash Register. Then We Asked an AI to Rob It — x402 Gateway on Arc", "summary": "An x402 payment gateway built on Arc by an unnamed development team charges per API request in USDC, with two pilot routes live behind a flag at $0.10 for a passport issuance and $0.02 for a premium FX feed. After 30 unit tests and 8 end-to-end tests passed, an Arc Studio adversarial AI audit returned a verdict of REQUEST CHANGES with 1 Critical, 6 High and 9 Medium findings, including a Critical flaw where payment settled on-chain but a database failure returned a 500 to the payer with no resource, no receipt and a spent nonce that made retry impossible. The team reports all 16 findings fixed with regression tests.", "body_md": "# We Gave Our API a Cash Register. Then We Asked an AI to Rob It — x402 Gateway on Arc\n\nAgents calling APIs have no checkout page or API key signup — they have a wallet. We built an x402 payment gateway on Arc: request → 402 challenge → signed USDC payment → resource, in one round trip. Two pilot routes live behind a flag ($0.10 passport, $0.02 FX feed), legacy rails untouched. Then an adversarial AI audit found the hole our 34 green tests missed: payment settled on-chain, accounting crashed, payer got a 500 with no receipt and a spent nonce. 1 Critical + 6 High + 9 Medium — all fixed with regression tests.\n\nAgents that call APIs have no checkout page, no credit card, and no API key signup — so we built an x402 payment gateway that charges per request in USDC on Arc. The flow is HTTP's forgotten 402 status finally doing its job: request → 402 challenge → signed payment → resource. Two pilot routes went live behind a flag: $0.10 for a passport issuance, $0.02 for a premium FX feed — while the legacy routes stay untouched. Then we pointed an adversarial AI audit at the money path, and it found the hole that would have taken real funds: payment settled on-chain, accounting crashed, payer got a 500 with no resource and no receipt — and the spent nonce made a retry impossible. One Critical, six High, nine Medium findings, all fixed with regression tests.\n\n## Why would a machine need a cash register?\n\n Because every other way of charging for an API assumes a human. Stripe checkout assumes a person with a card and a browser. API keys assume someone who registered an account first. An autonomous agent has none of that — it has a wallet. x402 is the pattern where HTTP status `402 Payment Required` becomes real: the server answers a request not with a login page but with a price tag, and the client retries the same request carrying a cryptographic payment proof. \n\nFor a junior: think of a vending machine instead of a supermarket. No account, no cart, no checkout wizard. You walk up with exact change, the machine prices the item, takes the coin, and gives you the thing plus a receipt — all in one interaction. Our gateway is that vending machine for HTTP resources, built on the payment rails from the previous episodes.\n\n## How does the 402 loop work?\n\nIn four layers, bottom to top. Everything the client sees is derived server-side — the price, the network, the recipient — so a client can never say \"I paid\" for a resource that wasn't charged.\n\n *Domain types live in the payments package; transport lives in the server; settlement stays in the existing seam.* \n\n1.  **Registry** — a`PaidResource` declares`id, method, path, priceUsd, network` . Unregistered routes pass the gate untouched, so the gateway is strictly opt-in per route.\n2.  **Price resolution** — a catalog-first`PriceResolver` , falling back to the registry's declared price. Resolved USD is converted to USDC atomic units at the boundary.\n3.  **Service facade** — builds the payment requirements, delegates verify+settle to the existing x402 seam (the same one the legacy routes use — we didn't reimplement settlement), appends a`UsageRecord` , and resolves`agentId` from the payer's wallet binding — or`null` when unbound.\n4.  **Middleware** — the Hono gate. No`PAYMENT-SIGNATURE` header → spec-compliant`402 + PAYMENT-REQUIRED` . Signature present → settle → record usage →`PAYMENT-RESPONSE` receipt header → serve the resource.\n\n *One round trip for the price tag, one for the goods. The receipt travels in the response header.* \n\n## What did the adversarial audit break?\n\n After the pilots shipped — 30 unit tests + 8 end-to-end tests, all green — we ran an Arc Studio adversarial review. Verdict: **REQUEST CHANGES** — 1 Critical, 6 High, 9 Medium. The green tests had covered the happy path and the \"payment rejected\" path. The audit covered the third path: *payment accepted, then something else breaks*. \n\n-  **C-1 — paid but nothing received.** Settlement succeeded on-chain, then a database hiccup in the usage-record write threw a bare 500. The payer's nonce was already spent, so a retry could never recover — no resource, no record, no receipt. Now: post-settle accounting is wrapped so a paid request*always* serves the resource and emits`PAYMENT-RESPONSE` ; failures are logged as reconciliation records instead.\n-  **H-1 — the free HEAD request.** Hono answers`HEAD` through the`GET` handler, but our route lookup matched methods exactly —`HEAD /api/v1/fx/delta/premium` skipped the gate entirely. Now HEAD is normalized to GET before lookup.\n-  **H-2 — client-controlled dedupe key.**`x-request-id` anchored usage dedupe; a client could reuse it across different payments and silently suppress records. The anchor is now the settlement tx — cryptographically unique per payment.\n-  **H-3 — charge first, fail later.** Settlement ran before the handler even existed in memory; a dead downstream engine meant a paid 503. A`preCheck` now refuses unbootable requests*before* the 402 challenge — you can't be charged for what can't be served.\n-  **H-5 — wrong attribution.** The usage record wrote the registry's declared network instead of what actually settled. Now it records`settle.sourceChain` , and the advertised accepts are filtered to the resource's own network.\n-  **H-6 — a mount that leaked.**`app.route(\"/api/v1\", passportRoutes)` exposed every future passport route under the paid prefix. The pilot now mounts the single handler explicitly.\n\n *The audit found the gap between \"payment succeeded\" and \"resource served\" — the seam every money path is made of.* \n\n## What's live and how do I try it?\n\n Behind `X402_GATEWAY_ENABLED` on Arc testnet — Arc USDC only in v1: \n\n-  `POST https://agentbadge.xyz/api/v1/passport/request` —`$0.10` , issues an agent passport (same handler as the legacy route)\n-  `GET https://agentbadge.xyz/api/v1/fx/delta/premium` —`$0.02` , premium FX-delta snapshot +`payment: {txHash, network, amount, receiptId}` in the body\n\n *The two pilot slots: same handlers as the legacy rails, now reachable by a machine carrying coins.* \n\n Registering a new paid resource is a registry entry, not a new code path: `{ id, method, path, priceUsd, network }`. The middleware, challenge, settlement, usage record and receipt come free. \n\n## What are the honest limits?\n\n-  **Pilots, not production.** Two routes, flag-gated, Arc testnet. The legacy passport rail and the Celo FX gate are untouched on purpose — migration is additive, never a silent swap.\n-  **No live numbers yet.** End-to-end is proven with the seam stubbed at the boundary (8 e2e tests). Real testnet txs through the gateway haven't run at press time — we say so rather than quote a receipt count we don't have.\n-  **Bearer payments.** A valid signature pays; it isn't bound to a specific resource by the wire protocol. That's x402's design, and the mitigation lives in the requirements the server derives, not in the client's wallet.\n-  **One audit.** Adversarial review we fixed and re-verified, not a formal verification. The regression tests — HEAD gating, zero-price, post-settle crash, engine-off refusal — are the artifact that outlives this article.\n\n The deeper principle is the same one the reconciliation episode ended on: **a chain payment isn't an event you receive, it's a claim you verify** — and this episode adds the other half: *once verified, everything after the money moves is customer service, and it must never cancel the sale.*", "url": "https://wpnews.pro/news/we-gave-our-api-a-cash-register-then-we-asked-an-ai-to-rob-it-x402-gateway-on", "canonical_source": "https://agentbadge.xyz/blog/arc-c50-x402-gateway", "published_at": "2026-11-14 00:00:00+00:00", "updated_at": "2026-11-14 20:23:15.206002+00:00", "lang": "en", "topics": ["ai-agents", "ai-infrastructure", "ai-tools"], "entities": ["x402", "Arc", "Arc Studio", "USDC", "Hono"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/we-gave-our-api-a-cash-register-then-we-asked-an-ai-to-rob-it-x402-gateway-on", "markdown": "https://wpnews.pro/news/we-gave-our-api-a-cash-register-then-we-asked-an-ai-to-rob-it-x402-gateway-on.md", "text": "https://wpnews.pro/news/we-gave-our-api-a-cash-register-then-we-asked-an-ai-to-rob-it-x402-gateway-on.txt", "jsonld": "https://wpnews.pro/news/we-gave-our-api-a-cash-register-then-we-asked-an-ai-to-rob-it-x402-gateway-on.jsonld"}}