We Gave Our API a Cash Register. Then We Asked an AI to Rob It — x402 Gateway on Arc
Agents 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.
Agents 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.
Why would a machine need a cash register?
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.
For 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.
How does the 402 loop work?
In 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.

Domain types live in the payments package; transport lives in the server; settlement stays in the existing seam.
- Registry — a
PaidResourcedeclaresid, method, path, priceUsd, network. Unregistered routes pass the gate untouched, so the gateway is strictly opt-in per route. - 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. - 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 resolvesagentIdfrom the payer's wallet binding — ornullwhen unbound. - Middleware — the Hono gate. No
PAYMENT-SIGNATUREheader → spec-compliant402 + PAYMENT-REQUIRED. Signature present → settle → record usage →PAYMENT-RESPONSEreceipt header → serve the resource.

One round trip for the price tag, one for the goods. The receipt travels in the response header.
What did the adversarial audit break?
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.
- 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. - H-1 — the free HEAD request. Hono answers
HEADthrough theGEThandler, but our route lookup matched methods exactly —HEAD /api/v1/fx/delta/premiumskipped the gate entirely. Now HEAD is normalized to GET before lookup. - H-2 — client-controlled dedupe key.
x-request-idanchored 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. - H-3 — charge first, fail later. Settlement ran before the handler even existed in memory; a dead downstream engine meant a paid 503. A
preChecknow refuses unbootable requests before the 402 challenge — you can't be charged for what can't be served. - 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. - 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.

The audit found the gap between "payment succeeded" and "resource served" — the seam every money path is made of.
What's live and how do I try it?
Behind X402_GATEWAY_ENABLED on Arc testnet — Arc USDC only in v1:
-
POST https://agentbadge.xyz/api/v1/passport/request—$0.10, issues an agent passport (same handler as the legacy route) -
GET https://agentbadge.xyz/api/v1/fx/delta/premium—$0.02, premium FX-delta snapshot +payment: {txHash, network, amount, receiptId}in the body

The two pilot slots: same handlers as the legacy rails, now reachable by a machine carrying coins.
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.
What are the honest limits?
- 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.
- 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.
- 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.
- 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.
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.