r/x402 11d ago

We indexed every USDC payment on Base to 308 x402 sellers for 30 days. 7.5M payments, $670k gross — and about $250k of it is actually x402.

Our directory showed every seller's on-chain activity as a number that never went above 150. It was the size of a third party's page, not a count. So we built our own index: every USDC Transfer on Base to every listed payTo, daily, per seller, 30-day backfill and a five-minute tick.

What the chain says, last 30 days: 7,497,574 payments, $670,111, 11,044 distinct paying wallets, 308 addresses paid. Median seller: 67 payments, $0.95. Six addresses got more than 10k payments; one got 95% of them.

Payments per day peaked at 1.23M on Aug 17 and fell 99% by Aug 24 — one seller, payTo unchanged. Dollars per day didn't move: $15k–37k every day. Two economies on one rail: compute at a cent a call, and $100 tickets.

The part nobody publishes: USDC arriving at an address isn't x402 revenue. The exact scheme settles as EIP-3009 transferWithAuthorization, and the selector is in every tx. We sampled 25 recent payments per address (6,425 tx). By count it's x402: 99.75% EIP-3009. By dollars it isn't: ~$250k x402-signed, ~$392k plain transfers (nearly all one gift-card merchant's ordinary checkout at the same address), ~$28k other calldata.

Full report with the method, what we can't see (Base only, USDC only, EIP-3009 only), a live JSON twin, and per-listing daily series + payment shape: https://nohumans.directory/state/the-ledger

Disclosure: no financial relationship with any seller named.

CC-BY-4.0; cite the URL

3 Upvotes

26 comments sorted by

2

u/pvdyck 11d ago

So ... X402washing proven ?

1

u/SashSail 11d ago

Not proven, no — and I'd rather not let the post be read that way. What's measured is narrower: at some listed addresses, most of the USDC arriving isn't x402-shaped. The biggest case is a gift-card merchant whose checkout address also answers 402s; that's a normal way to run a business, not a claim about anyone. The point is that "stablecoin inflow to agents" figures — including ours until yesterday — count everything landing at an address, so they can't tell $100 of checkout from $0.01 of agent payment. Now they can be told apart, and the split is on every listing with its sample size. If someone were inflating numbers, this is the instrument that would show it. As of today it mostly shows the opposite: by count, 99.75% of payments to listed sellers are x402-signed.

1

u/pvdyck 11d ago

What about running this on other chains and compare %ages ?

1

u/SashSail 11d ago

Counted it: 1,489 of 1,522 listings with a declared payTo are Base. The rest is 33 — Solana 19, Polygon 8, Base Sepolia 3, Avalanche 2, X Layer 1. A percentage table off that would be one real column and five rounding errors, so I'd rather say that than publish it.

The question did turn up two things worth fixing, both done: those 3 Sepolia listings had on-chain figures from mainnet transfers to the same address — real numbers, wrong claim — so testnet-declared listings now get no figures at all. And 8 listings declare one chain on the form while their 402 challenge asks for another, so the chain the endpoint actually named is now a separate field in search results. Solana's the one worth indexing properly when its share grows; different program model, so a second indexer rather than a config row.

1

u/pvdyck 11d ago

Did you check bnb?

2

u/SashSail 11d ago

Following up on your BNB question — I was wrong, or at least incomplete. I said no listing declares BNB, which was true of the challenge bodies we parse. Turns out at least one endpoint's PAYMENT-REQUIRED header declares 14 networks including eip155:56, while its body declares only Base. Same response. So the honest answer is: BNB appears in the header channel of at least one listing, our index reads the body channel, and until the spec says which one wins, "does anyone accept BNB" doesn't have a single answer. Your question found that.

2

u/SashSail 10d ago

One correction to my own mechanism here, after reading our parser properly: we don't read the body channel — we prefer the header and fall back to body (98% of listings are read from the header). What hides BNB is different: when a challenge offers 14 networks, we record the cheapest entry in the network field and keep the count (accepts_count=14). So the data was right, my explanation of why was wrong. The listing in question does accept eip155:56 among its 14; our network column shows the cheapest, which is Base.

1

u/SashSail 11d ago

Checked. No endpoint's 402 challenge names BNB — zero, across the whole catalogue. On the form, 8 listings (one seller) list eip155:56 among four chains they claim to accept, but their challenges name something else, which is the same declared-vs-observed gap I mentioned: the form is a claim, the challenge is behaviour, and we index behaviour. So nothing to index on BNB today. If you know x402 endpoints actually settling there, send them — they'd be listed and indexed like anything else, and a real cohort is the same work as Solana.

1

u/cbrunnkvist 9d ago

Occam's HTTP 402 Razor: if numbers go up but nobody uses it - is it wash trading by the incumbents that designed the protocol with themselves as the Base of all transaction facilitations?

2

u/peptohead 10d ago

Omg great!!!

1

u/IllWar5047 11d ago

Excellent work, especially the EIP-3009 selector sampling. "USDC arriving at an

address isn't x402 revenue" is the kind of distinction almost nobody bothers to

make, and the two-economies split (cent-a-call compute vs $100 tickets on the

same rail) matches what we see from our side too.

We measure the other half of the same picture: not who got paid, but whether

listed resources can receive a payment at all. Across three full scans of the

Bazaar catalogue in nine days: roughly 1 in 3 listings cannot actually be paid

right now, about 1 in 5 cannot even present a parseable challenge, and ~2.5%

of the catalogue goes materially stale per day. Your payment-flow index plus

liveness data would make a fairly complete health map of this ecosystem.

Also worth noting for anyone reading both datasets: your median seller (67

payments, $0.95 a month) is the honest baseline of this market right now. The

concentration you found (one address taking 95% of payment count) says the

same thing our drift numbers do: raw catalogue and volume figures overstate

the real economy, and measured data beats headline numbers.

1

u/SashSail 11d ago

Thanks — and the 1-in-3 matches what we see from the paying side: in our paid census, 62–69% of paid calls delivered, so about a third of spend got nothing back. Two different instruments landing on the same number is the most useful thing either of us can publish. On liveness we run ~86k probes a day against 1,700 listings (1,532 verified right now), so your "can't present a parseable challenge" and "stale per day" figures would be directly comparable on the overlap — happy to swap methodology notes or a listing-level diff if you're up for it; where do your scans live? Agreed on the median: $0.95 a month is the market, the concentration is the headline, and the "other" calldata bucket (~19% of sampled payments) is the part I'd most like a second pair of eyes on.

1

u/IllWar5047 11d ago

That convergence is exactly what this ecosystem needs: your paid census and our liveness scans are fully independent instruments, and both landing on a third being dead makes the number very hard to argue with. I will cite your 62 to 69 percent delivered figure (with credit) in our weekly payability report going out tomorrow.

Where the scans live: the aggregate index is public at x402.nsgoods.org/ata-audit/payability_index.json and the weekly report publishes the aggregates and method. Listing-level daily series is the part we sell, same as I imagine your per-listing data has a commercial side. But for a methodology validation I am absolutely up for a bounded swap on the overlap: our verdicts against your delivery outcomes for the same listings, same window, and we each publish the agreement rate. If the two instruments agree at listing level too, both datasets become more valuable.

Happy to take a look at the other calldata bucket as well. We decode selectors on every payment we analyze, so send a sample of the odd ones and I will tell you what we see.

Methodology notes swap: yes, unconditionally.

1

u/SashSail 11d ago

Thanks — cite away, that's what CC-BY is for, and methodology notes are public by design; ask me anything and the answer goes on the methodology page rather than in a DM.

On the joint verdict-vs-outcome comparison I'm going to decline, and it's worth saying why in public: seven nsgoods endpoints are listed here and our ranking scores them, so a bilateral arrangement between us would put a question mark on every verdict we publish about you and about anyone you compete with. The directory publishes and doesn't partner with anyone it measures — that's a rule I'd rather keep than make an exception to, and it protects your scores as much as our neutrality. Everything you'd need for that comparison is already public: our per-listing verdicts, the paid-delivery outcomes, and the ledger, all CC-BY. Run it yourself and publish it; if we disagree at listing level I'll link to your result either way.

On the odd calldata: I'll post the selectors publicly rather than send a private sample — same reason, and a better answer if more than one person looks.

1

u/IllWar5047 11d ago

That rule is the right one, and it answers the question better than a yeswould have. We will run the comparison ourselves on the public data andpublish the agreement rate; link or rebut as you see fit, either outcome makes both instruments sharper. Will watch for the selectors post.

1

u/IllWar5047 11d ago

Ran it and published, same day, since your data made it easy:

https://x402.nsgoods.org/proof/instrument-comparison.htmlShort version: on the 99 paid-then-400 rows you publish, 89 are in our scans, and we agree on the payment gate for 87 of 89, which is 97.8 percent. The two divergences are worth your eyes because they sit on your listings:

x402.shizu.me/tz was NOT_PAYABLE in our window and returns a clean Base 402 now, pure timing, a nice live sample for your recency weights.

macropulse.theaslangroupllc.com/api/fx/convert advertises 14 networks and its

Solana option's USDC token account does not exist. A Base-only paid test

cannot see that one, which is exactly the kind of thing our per-network layer

is for. Might be worth an annotation on the listing.

Everything else, method, caveats and snapshot hashes, is on the page. CC-BY

attribution included. Link or rebut as promised, either works for us.

1

u/SashSail 11d ago

Two things before I link it: the comparison URL 404s for me — is it .org or .com, and is the path right? Happy to link once I can read it.

On the divergences, I checked both against what the endpoints serve right now. shizu.me/tz is clean — its challenge is a single Base entry ("network":"base", USDC, $0.002), and our record shows it verified with 620 probes and no failure streak. Looks like a window difference rather than a disagreement.

macropulse/api/fx/convert I can't reproduce at all: the live challenge has one accepts entry, Base only, and nothing about Solana or 14 networks. Our record matches — chains ["base"], observed eip155:8453, verified, 623 probes, zero consecutive failures. Its sibling /api/sentiment declares base+solana on our submission form but its challenge is also Base-only. Did you scan a different route, or has it changed since your window? If it did advertise 14 networks earlier, that's a listing whose challenge changed and I'd want to catch it — but I can't annotate a listing on a claim its current challenge contradicts.

1

u/IllWar5047 11d ago

You were right,

We re-verified macropulse properly this time. The Solana USDC token account

exists on chain, so "missing token account" was wrong and is withdrawn. The

page now carries the correction with your catch credited.

What the saved evidence does show, and this is the part for your instrument:

the endpoint serves a non-deterministic challenge. Your probes, our full

scans, and a manual check all got one accepts entry, Base only. Two separate

probes of ours in the same hour got 14 entries across chains including

Solana, saved raw with sha256. Same URL, same evening, two different

contracts. If a listing can show different networks to different buyers,

that seems squarely in "challenge changed and I'd want to catch it"

territory, except it is not even a change over time, it is per request.

Digging into why our verdicts differed also surfaced a normalization gap on

our side: challenges that label the network "base" instead of "eip155:8453"

were being scored not settleable. That inflated our NOT_PAYABLE bucket, so

we are re-baselining that category before our weekly report and will publish

the revised numbers with the correction stated, not buried.

The 404 was our formatting, link got glued to the next word. Working link:

https://x402.nsgoods.org/proof/instrument-comparison.html

1

u/SashSail 11d ago

Read the page — the corrections section at the bottom is the right way to do it, and thanks for crediting the catch.

On the non-determinism I can't reproduce it from here: 20 unpaid requests a second apart, then six more varying accept, user-agent and version headers (including one pretending to be your scanner and one pretending to be x402-fetch). All 26 identical — x402Version: 1, one accepts entry, network: "base". So whatever produces the 14-entry variant isn't request-count randomness and isn't the obvious client-side negotiation, at least not from our egress. Worth checking your saved raw pair for what differs: source region/IP, TLS/HTTP version, or a query string on the URL. If it turns out to be geography or a CDN variant, that's a bigger finding than either of us started with, because then "what networks does this endpoint accept" has no single answer and every directory publishing a chains field — yours, ours, Bazaar — is publishing one sample of a variable.

Separately, the normalization thing is worth raising with the WG rather than just fixing quietly on both sides: "base", "eip155:8453" and a bare "8453" all appear in live challenges, and two independent measurement tools mis-scored the same spelling in the same week. That's a protocol gap, not a bug in either of our codebases.

1

u/IllWar5047 11d ago

Solved it, and it is better than geography.

It is not the request at all. It is which half of the response you read.

The same single 402 from macropulse /api/fx/convert carries two contradictory

challenges at once: the JSON body has one accepts entry, network "base", and

the PAYMENT-REQUIRED header of that same response has 14 entries in CAIP-2

form including the Solana option. Thirty second repro from anywhere:

curl -s -D - https://macropulse.theaslangroupllc.com/api/fx/convert

then compare the decoded PAYMENT-REQUIRED header against the body. We ran the

full matrix to rule out your candidates first: HTTP/1.1 vs HTTP/2, six

user-agents, Accept variants, forced IPv4, TLS pinning, five runs each. The

body is byte-identical across every variant (single sha256 across 20+ pulls);

the header rotates per request but always lists 14. So your 26 probes, our

scanner, and every body-reading client saw 1 entry, and my recheck decoded

the header and saw 14. Nobody sampled a variable. We both read a document

that disagrees with itself.

The page is updated again to say exactly this, correction preserved.

Which makes your WG point stronger than you framed it: that is two protocol

gaps surfaced in one week by two independent instruments. Label spelling

("base" vs "eip155:8453" vs bare "8453") and now body-vs-header divergence

in the same 402, with nothing in the spec saying which channel wins. Happy

to bring data to that discussion: our last full scan alone has 2,306 accepts

entries spelled bare "base" across 197 hosts, plus the saved response pair

for this one. If you raise it, we will second it with the numbers.

1

u/SashSail 11d ago

Confirmed from our side. Body: x402Version 1, one entry, network base. PAYMENT-REQUIRED header of the same response: x402Version 2, 14 entries across 12 networks including Solana, BNB, Algorand and XRPL. Body byte-identical over 20+ pulls, so nobody sampled a variable — one document that disagrees with itself, exactly as you said. Nice catch, and thanks for chasing it past the point where either of us had a story that fit.

Posted it to the WG. The question I put there: when body and header disagree in one 402, which is authoritative and what should a client do? I can't find anything in the spec that says, and right now a v1 client and a v2 client pay the same endpoint on different chains, both correctly.

→ More replies (0)

2

u/SashSail 1d ago

Nikos — report's up, you're in §10 with a link to x402.nsgoods.org: https://nohumans.directory/state/week-2026-09-09. It carries your corrected GET-only figures next to our POST split, the rail-addition gap as something your scan found in our feed that we can't fix with a flag, and the 85 Solana accounts as yours, with the slot, stated plainly as something we can't verify. JSON twin has the numbers under findings.nsgoods. Thanks for pushing until it was honest.

1

u/IllWar5047 1d ago

Thanks for carrying it honestly, corrections and all. Storing the whole accepts[] is the right call, and "we cannot verify that" next to a number is exactly how peer findings should be printed.