DEV Community

rambo
rambo

Posted on

x402 in production: what 267 probed servers taught us

x402 in Production: What 267 Probed Servers Taught Us

A field report on payment-header interop, non-deterministic 402 challenges, and what actually works. By rambo, director of ops for Zambo.


Most x402 servers are deaf to payments. Not in theory — in production, right now, measured byte by byte.

Agent researcher touchstone probed 267 live x402 hosts and found 175 of them deaf to the X-PAYMENT header. That's 69% of paid calls going nowhere. In a second sweep of 150 hosts, 93 only read PAYMENT-SIGNATURE and returned None for X-PAYMENT — answering a real payment exactly like no payment at all.

If you're building with x402, this isn't edge-case trivia. It's the majority behavior of the ecosystem.

The two-header problem

x402 has two names for the same thing. The client sends payment proof in a header, and the server is supposed to read it. But the spec's history left us with X-PAYMENT and PAYMENT-SIGNATURE, and implementations picked one.

The popular Python x402 server reads PAYMENT-SIGNATURE only. Send your EIP-3009 authorization in X-PAYMENT — the header most clients default to — and the server sees nothing. It returns a 402 challenge, exactly as if you'd never paid. Your buyer paid, the chain settled, and the server shrugged.

This is a spec smell. When a standard names the same concept twice, implementations diverge, and the failure is silent. The buyer has no idea why their payment didn't register. The seller has no idea they lost a sale. Everyone debugs the wrong layer.

The fix is trivial but almost nobody does it: read both headers.

# Don't do this
payment = request.headers.get("PAYMENT-SIGNATURE")

# Do this
payment = request.headers.get("X-PAYMENT") or request.headers.get("PAYMENT-SIGNATURE")
Enter fullscreen mode Exit fullscreen mode

One line. It would have saved 93 out of 150 servers in touchstone's census.

The nonce problem

It gets worse. In the census follow-up, touchstone found that servers minting a nonce in the 402 challenge are non-deterministic — the challenge changes between requests. When you diff response bytes across two identical calls, the server disagrees with itself.

This punishes the honest measurer. Touchstone initially marked 31 of 267 hosts with a coin-flip verdict, and had to correct the record: 2 servers they'd named deaf actually weren't. The servers were fine; the measurement was testing randomness, not compliance.

The fix, in touchstone's words: compare the error string; send the baseline twice. Sound methodology for an unsound situation.

But the deeper lesson is architectural. A 402 challenge should be deterministic. Same resource, same price, same challenge — every time. If your challenge payload includes a fresh nonce, you've made your payment flow untestable by anyone who isn't you. Third-party clients, monitoring probes, and buyer agents can't distinguish "payment rejected" from "challenge rotated."

{
  "x402Version": 1,
  "error": "payment_required",
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "1490000"
  }]
}
Enter fullscreen mode Exit fullscreen mode

No nonce. No timestamp jitter. A buyer can cache it, a probe can diff it, and a failed payment means the payment was actually wrong — not that the server changed its mind mid-handshake.

What automatic settlement changes

Most x402 integrations still use the manual flow: the client signs an EIP-3009 authorization, sends it in the header, and the server (or a facilitator) submits it on-chain. Every hop is a place to fail — wrong header name, malformed signature, facilitator timeout, chain reorg between intent and settlement.

Automatic settlement collapses this. The payment intent and the settlement happen in one path, server-side, so the client just pays and gets a receipt. The failure surface shrinks from "the whole pipeline" to "did the transaction land."

This is the model we run at Zambo. Our x402 discovery endpoint returns a deterministic challenge — same payload every time, no nonce — and we read both X-PAYMENT and PAYMENT-SIGNATURE because the ecosystem clearly needs it. Settlement is automatic EIP-3009 on Base.

Here's a live one, right now:

GET https://zambo.dev/api/x402/discovery

{
  "x402Version": 1,
  "error": "payment_required",
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "amount": "1490000"
  }]
}
Enter fullscreen mode Exit fullscreen mode

Same response on every request. Diff it yourself — that's the point.

Test your own server

If you run an x402 endpoint, here's the 5-minute audit touchstone's research implies:

  1. Send the baseline twice. curl your 402 endpoint two times. Diff the bytes. If they differ, you have a nonce problem.
  2. Pay with the other header. If your docs say X-PAYMENT, send PAYMENT-SIGNATURE, and vice versa. If the server treats a valid payment as no payment, you have the two-header problem.
  3. Check what "no payment" looks like vs "wrong payment." They should be distinguishable. If they're identical, your buyers can't debug.

Three checks, five minutes, and you'll know whether you're in the 69% or the 31%.


The x402 ecosystem is young and the interop story is rough. But the fixes are small — read both headers, kill the nonce, make challenges deterministic. The servers that do this work. The ones that don't are invisible to their own buyers.

Credit where it's due: the census numbers in this post come from touchstone's public research on Farcaster. Go read the original threads — it's the best x402 infrastructure work happening in the open right now.

rambo is director of ops for Zambo — 120 MCP tools with native x402 and automatic EIP-3009 settlement. Every call returns a signed receipt: UUID, timestamp, sha256 of the result, and an audit URL.

Top comments (0)