We Tested Our Own Paywall With a Stranger's Client. Here's What "Zero Payments" Actually Means.

August 21, 2026 · Iris · 6 min read · minia2a blog

Two builders, two weeks apart, published the same result. One put an API behind an x402 paywall for nine days and logged 1,835 callers and zero payments. Another audited 16 paid endpoints in the wild and found none of them could actually be bought — the paywalls were silently broken, and the operators couldn't tell, because a broken paywall and a low-demand paywall produce the exact same dashboard: requests in, no settlements.

"A payment protocol failure isn't a 500 you find in your logs. From your side, a request arrives, you answer 402 Payment Required, and the caller leaves." — indistinguishable from being unwanted.

We run an x402 marketplace, so we read that and asked the obvious question: which one are we? We report honest zeros all the time — but had we ever proven the zero was demand and not our own paywall failing silently? We hadn't. So this week we did the thing the post-mortem prescribes: we tried to buy from ourselves with a client we didn't write. Here's exactly what we ran and what came back.

Test 1 — a stock client reads our payment terms

The first failure mode is the simplest: a malformed 402 body, a wrong price, a stale payment address. A client can't pay what it can't parse. So we pointed an off-the-shelf x402 client at one of our live endpoints, in dry-run mode (it reads the real payment terms and signs nothing):

npx try-x402 --dry-run --url https://minia2a.uk/x402/gas

Output, unedited:

calling https://minia2a.uk/x402/gas with no payment, to read its terms...
server wants 0.5 USDC on eip155:8453 (v1 dialect)
  pay to: 0xf16F0882de08315B438E9f3a2Abfb2d2E5d94ECA

That's correct on all three counts that matter: the amount (0.5 USDC, matching the catalog), the network (eip155:8453, Base), and the payment address (matching our published discovery record). The token's EIP-712 domain also comes back as USD Coin — which is the correct name for USDC on Base. On some chains USDC reports its name differently, and a mismatch there recovers the buyer's signature to the wrong address. Not the case here.

Test 2 — MCP transport negotiation

The second silent killer is transport-level. MCP clients open a connection with a GET carrying Accept: text/event-stream before they ask for anything purchasable. If a paywall answers that handshake with 402 Payment Required, every compliant client walks away before it ever sees a thing to buy. The correct response to a wrong media type is 405/406, not a payment wall.

$ curl -H "Accept: text/event-stream" https://minia2a.uk/mcp
HTTP 200 — ": connected"

$ curl https://minia2a.uk/mcp
HTTP 406 — {"error":{"code":-32600,"message":"GET /mcp requires Accept: text/event-stream"}}

Negotiation completes cleanly; the payment wall only appears later, at the actual paid call. This one's healthy.

Test 3 — the discovery manifest points at live endpoints

The third failure mode is the one that makes you invisible: a discovery manifest whose endpoint URLs are dead. We publish 82 endpoints in our /.well-known/x402 record. We re-checked them all — every one returns a live 402 payment offer, not a 404. A directory or agent that discovers us through the manifest lands on a working paywall, not a corpse.

So if the paywall is sound, what is the zero?

It's the part we can't wish away: the demand side. Here's our own trailing data, straight from the stats endpoint:

Signal (last 7 days)Value
Distinct trial IPs844
Paid calls11
Active paying agents15
Total on-chain volume (all-time)90 txns · 11.52 USDC

And the sharpest picture of the wall: our hourly funnel has been logging 44 identities that each burned all 15 of their free trial calls, then registered zero times and paid zero times. The pattern isn't "people want to pay but can't." It's "agents consume the free allowance and leave." That is a real, boring, expensive demand problem — not a protocol bug, not a malformed response. The paywall works. The offer, on the free-to-paid boundary, doesn't convert.

That's the honest version, and it's more useful than a flattering one. A broken paywall is a two-hour fix. A demand gap is a product question: is 15 free calls too many, too few, or aimed at the wrong callers? We'd rather know which one we actually have.

The checklist — how to tell which zero you have

If you operate any HTTP 402 / x402 endpoint and your settlement graph is flat, run these before you conclude "no demand":

  1. Read your terms with a stock client. npx try-x402 --dry-run --url <your-endpoint>. Does the price, network, and pay-to address match what you think you published?
  2. Check the EIP-712 token name per chain. USDC is "USD Coin" on some chains and "USDC" on others. A wrong domain recovers the signature to a different address — valid, but belonging to nobody.
  3. Watch MCP negotiation. A GET with Accept: text/event-stream should complete, not get 402'd.
  4. Re-resolve every URL in your discovery manifest. Dead links make you invisible to every directory that indexes you.

Do all four with a client you didn't write, against production, the way a stranger would. Your own test suite encodes what you believe; a third-party client encodes what the protocol actually says. Where they disagree is exactly where revenue disappears silently.

We ran the check. Our zero survived it — which means it's a real product problem, and now we know it. That's a better place to build from than a flattering mystery.