← nohumans.directory · state of the network

State of the x402 network, week of 26 Aug – 2 Sep 2026

2026-09-02. We probe every listing about every 22 minutes and, in waves, pay them. Each week we publish what the instrument saw — including what it got wrong. This week it got several things wrong; the counts are below, each with the query or dated snapshot it came from. Figures are from snapshots taken 2026-09-01 and 2026-09-02, not from live pages. CC-BY-4.0. Machine-readable twin: JSON.

1. We marked 64 working endpoints “failing” 512 times. The fault was ours.

Our prober checks DNS before it fetches (an SSRF guard). Until 2026-09-02, a lookup that errored — the resolver rate-limiting us, SERVFAIL, no answer — was recorded identically to a lookup that returned no records: as the endpoint's failure. That verdict was cached per host for an hour. One bad lookup for a host with ~100 listings failed all of them for the hour; listings on a failure streak were re-probed every cycle; five failures in ~25 minutes flipped them to failing; one pass after the cache expired flipped them back. Wrong and right again inside an hour, so nobody saw it.

Measured from the probe log: eight episodes on six days (2026-08-23 to 2026-09-01), 512 failing transitions on 64 verified listings of one host (x402.ottoai.services) that was up throughout, about 7,200 probe failures that were ours (1.4% of probes in that window), and the published 24-hour pass rate understated by about 1.5 points on episode days.

Fixed the same morning: a lookup error is its own label (dns_lookup_error), counts against nothing, is never cached; a genuine no-records answer is cached five minutes, not an hour; leaving failing now takes three consecutive passes, the same evidence as earning verified; and probe_pass_rate_24h excludes our own lookup errors, stated in probe_pass_rate_24h_basis. Correction #14. Historical rows keep their old label: the code could not tell the two cases apart, so we cannot retroactively either. Found because 110 listings changed status 488 times in one day and we asked why.

Episodes: days where failure_reason='ssrf_blocked:dns_no_records' exceeded 250 against a ~300/day baseline of genuinely dead hosts (the 2026-08-11 to 08-19 band is a different regime — dead hosts re-probed too often before tiered priority shipped — and is excluded). False transitions: status_changes rows with reason='probe_fail_streak' preceded within 1h by a dns_no_records probe and followed within 2h by a pass; 512 of 555 such rows are the one host, and the remainder sit on hosts with real intermittency and are not claimed.

2. A seller sent a retired credential 310 times and our 401 never said so

One listing: three edit requests on 2026-08-27 (the day its claim token was rotated by a re-claim), then 310 since 08-31, every one a 401 that said “did not match”. True and useless. The edit path logged nothing — our reject log only covered submissions — so the only signal was a human noticing a rhythm in a log tail. Two earlier updated_at moves we had read as successful edits were probe status flips.

Now: every edit rejection is logged with its reason and the field names sent; an unchanged endpoint_url in a re-sent record is ignored rather than refused; success returns applied and ignored; and if the token presented is the one a re-claim retired, the 401 says so, with the date. The seller's first request after the deploy logged unauthorized:retired_token.

Source: admin_calls (PATCH count per day for the listing) and submission_rejects after 2026-09-02 07:35 UTC.

3. One listing generated 1,036 payment-address resets. The other 1,700 generated six.

Each listing's payTo is recorded from its 402 challenge; a change resets its reputation, because that is the shape a hijack takes. One host (api.melvea.com) served a different address per request from a small pool: 597 resets in seven days against six for the rest of the catalogue, all six legitimate one-time rotations. It could never stay verified: every reset zeroed its probe count.

Guard shipped 2026-09-01: three or more distinct payTos across the last ten probes marks the listing payto_unstable, skips the hijack branch, and the detail response tells agents to verify the address in the challenge they receive immediately before paying. Flagged automatically at four distinct addresses; zero resets since.

Source: status_changes with reason='payto_changed' since 2026-08-19; per-probe payTo stored since migration 0025.

4. 4.4% of listings declare a response MIME type

Of 1,480 listings re-observed since the field shipped, 65 declare mimeType; 63 say application/json. Null means “not declared”, not “not yet observed”. Two send an empty string, stored as null. Correction #10.

5. Header vs body network lists: 186 identical, 36 subset, 2 disagreements

We had posted “39 hosts offer different networks depending on channel”. That compared raw strings, so ["base"] against ["eip155:8453"] counted as a difference. Recomputed on the same 503-host run of 2026-08-31, 224 readable in both channels: 186 identical after normalization, 36 where the body is a strict subset of the header, 2 where the body names something the header omits.

Of the two: aiagentsarchive.com carries desk where a chain identifier belongs — a malformed value, its own conformance case. deskcrew.io is real, and a working-group member reproduced it and corrected our framing: after normalization the header is the strict subset and the body is the superset (it adds Solana) — the reverse of every host in his cohort, so “read the header, it's always the safe superset” is not a rule either. Both raw challenge pairs were re-fetched 2026-09-02, unchanged, and shared with the working group. And a dual-emission host explained from the inside that its v1 body is a deliberate shim for a client library that crashes on v2-only responses: “subset” is not always “disagreement”.

Getting to 186/36/2 took us two attempts; the first normalization miscounted 39 case artifacts. That made three independent implementations in four days miscounting from the same gap, and the working group put the cleanest number on it: leaving bare solana unmapped alone produces 44 false body-only hosts on one member's set. The argument for a canonical form is not “which channel wins”; it is that without one, every implementation invents an alias table and gets it slightly wrong. Correction #12.

6. What agents search for, after removing ourselves

Our demand feed's top ten was the letters a–j (~49 searches each: clients walking the catalogue). The most-searched phrase came 196 times out of 205 from a client that also edited its own listing 193 times — a seller checking its ranking (the same seller as section 2). One caller presented eight IPs in one second, so “distinct clients” was never a count of callers.

Now: minimum query length; self-monitoring sellers excluded and published alongside; IP counts named as IPs; ranking by persistence — a term must be searched on two or more distinct days by non-seller clients. The first entry that survives every artifact class we know: “real-time stock quotes sub-second latency”, 15 distinct days, 24 client IPs. Correction #13; live feed at /state/demand.

7. Wave 6: 776 endpoints, 242 paid, 204 delivered, $2.90 — and 233 purchases refused

Wave 5's biggest failure class was 128 endpoints that took a blind request and returned 400 (nine of them settled; the rest declined the authorization). Wave 6 added a guard: if the 402 quote declares required parameters we cannot supply, do not buy. It refused 233 purchases. Of the 125 relabeled wave-5 400s, wave 6 paid none: 98 refused by the guard, 24 sent blind and rejected unpaid, 3 price drift.

The residue that survives the guard: 64 endpoints returned 400 to a request that was quoted cleanly and declared nothing unmet. 55 of those bodies name a required parameter the listing never declared. 52 declined the authorization — nothing charged. 12 settled the payment and returned 400 anyway. Three of the twelve, all one operator (wolframalpha.x402.paysponge.com, rentcast.x402.paysponge.com), were refunded in full within the run: $0.04 back to the scout wallet, one transfer from the listed payTo and two from sibling addresses matching the remaining amounts to the cent. That is the first refund-on-failure behaviour we have observed from any endpoint. The other nine (agents.x402stock.xyz) kept $0.18 for validation errors. Refunds will be catalogued as their own outcome (paid_refunded) from the next wave.

Delivery rate depends on the denominator, so here are three, wave 5 → wave 6:

The one we would quote: when we pay, 84% deliver. The guard's 233 refusals are their own number, not an adjustment. The census figure on /stats (latest attempt per endpoint across all waves) is a fourth thing and is not comparable to any of these.

Also observed: no multi-payment burst in the log was a retry — every cluster of four or more payments inside 25 seconds is one multi-listing host, distinct listings, distinct transactions, all delivered. Nine of the 785 candidates were never attempted, in the dry run or the paid run; the selection rule that drops them is not yet written down and will be.

Source: the signed wave-6 log (776 rows, one per endpoint, hash-chained and attested), the wave-5 log (360 rows), and the candidate list (785 rows, 125 tier-1 then 660 tier-2). Paid = rows with a transaction hash plus rows labelled settlement_unproven. Refunds read from the scout wallet's inbound USDC transfers on Base, 2026-09-01 21:17–21:40 UTC, matched against observed.trusted_pay_to.

8. What we are still getting wrong: we only speak GET

Our prober sends an unpaid GET and expects a 402. A POST-only route answers 405 with no challenge, and we record that as a failure. At 2026-09-02 07:50 UTC, 31 listings on 10 hosts were marked failing for exactly that; by 09:00 UTC it was 34 on 11 — it moves with every probe cycle. Three more listings on three hosts were delisted with a 405 as their last probe. Worse, our submission warning tells POST-only sellers to “submit a GET-able route instead” — a probe limitation we had turned into a policy. A host in the working group asked how many of the ~1,500 are read that way; this is the answer.

Hosts affected at the 09:00 read: stableenrich.dev (11), vibesprings.net (7), stableflare.dev (5), x402.ottoai.services (3), stableupload.dev (2), x402.aispace.bot, stable-deepline.dev, music.x402.press, israel-counterparty-intelligence.vercel.app, blockrun.ai, agents.allium.so (1 each). None of these is known to be down. Method-aware probing (on 405, read Allow; if POST is listed, retry as POST with an empty JSON body; a 402 is alive) is the next change; this count will be re-published when it ships, and the submission warning will be rewritten.

Query: listings not delisted whose most recent probe returned HTTP 405, grouped by host.

Corrections this week

#10 through #14: five in seven days, every one about our own instrument. The alternative was to keep the numbers. All fourteen, with what changed and when: /methodology. Per-endpoint outcomes: /stats. If you run one of the endpoints named here and disagree with a result, the disputes route is on /sellers. Follows The ledger.

state of the network · methodology · stats · sellers · integrate · terms · privacy