Last week we counted reachable. This post counts
parseable: how many of the live 402 bodies clear the Zod
schemas shipped by three parsers — the frozen legacy v1 npm
client [email protected] (last published 2026-04-16),
the v2-aware @x402/[email protected] /
@x402/[email protected] (shipped 2026-09-29), and the python
facilitator parser x402==2.25.0. For 280 live 402
bodies on 84 ERC-8004 agents: 49 parse under v1
(17.5%), 249 parse under
@x402/[email protected] at the per-accepts-entry level
(88.9%), and 262 parse under python (93.6%).
Of the 231 bodies v1 rejects, 200 now parse under v2.
The remaining 31 v2 rejections are two single-seller bugs plus a
handful of non-JSON responses — detailed below.
Companion to the payability census (0946) and the interop field test (0942) · CC BY 4.0.
The numbers
| Validator | Parses | % | Status |
|---|---|---|---|
Legacy v1 npm [email protected] Zod schema (vendored, last published 2026-04-16) | 49 / 280 | 17.5% | Frozen; six months since last release |
v2-aware npm @x402/[email protected] / @x402/[email protected] — per-accepts-entry PaymentRequirementsSchema union | 249 / 280 | 88.9% | Current; shipped 2026-09-29 |
Same v2 client — top-level parsePaymentRequired discriminated union (also enforces top-level resource for v2) | 228 / 280 | 81.4% | Stricter than per-entry |
Python x402==2.25.0 parse_payment_required | 262 / 280 | 93.6% | Current; lenient facilitator-side parser |
| v1 pass & v2 pass (both v1-pinned and v2 buyers can parse) | 49 / 280 | 17.5% | v1 is a strict subset of v2 |
| v1 reject & v2 pass (upgrading v1-pinned buyer unlocks) | 200 / 280 | 71.4% | The “upgrade-and-you-get-this” delta |
| v1 reject & v2 reject (unparseable in either npm runtime) | 31 / 280 | 11.1% | Three distinct seller-side bugs — see below |
17.5% is the number that matters if you are still pinned to
[email protected]: everything that goes through that
Zod PaymentRequirementsSchema is held to it, one bad
field in accepts[0] rejects the whole array at parse
time, and the client never attempts to pay. 88.9% is what
the v2-aware @x402/[email protected] actually gets.
93.6% is what a lenient facilitator-side parser sees. The gap
between v1 and v2 is almost entirely the
v1-vs-v2 version split, not a correctness problem
on the seller side; the gap between v2 and python is three
single-seller bugs we characterise below.
The npm landscape, as of this probe
-
Legacy v1 line (frozen):
[email protected]and[email protected], both last published 2026-04-16. These are what we tested against. No new release in six months. Any buyer that pinned a^1.2.0at the time still sits here today. -
Current v2 line:
@x402/[email protected]and@x402/[email protected], published 2026-09-29.@x402/coreexposesPaymentRequirementsV1Schema,PaymentRequirementsV2Schema, and a unionPaymentRequirementsSchemathat accepts both v1 and v2 accepts entries. Measured against this schema on the full dataset: 249 of 280 bodies (88.9%) parse at the per-accepts- entry level; 228 of 280 (81.4%) parse at the top-level discriminated union. The 200-body delta over v1 is almost entirely the v2-only bodies v1 cannot discriminate. -
Downstream Coinbase packages:
@coinbase/[email protected](published 2026-10-06) depends on@x402/fetch@^2.0.0,@x402/evm@^2.0.0,@x402/svm@^2.0.0, and@coinbase/x402@^0.6.3— which in turn depends on@x402/core@^2.0.0. A current AgentKit buyer is on the v2 line.
This is the correction worth making loudly: a 2026-10-12 census
against [email protected] is not a census
against the npm client a current AgentKit buyer actually links. It
is a census against the client any v1-pinned buyer still
links — a population that was most of the ecosystem through
summer 2026 and is now shrinking as projects upgrade.
Methodology
We started from the 280 endpoints that returned HTTP 402 in the
2026-10-11 payability probe
(previous post:
412 probed, 280 valid 402, 132 non-402). We re-probed each endpoint
one more time on 2026-10-12 at ≤2 req/s with a signed User-Agent,
never sent an X-PAYMENT header, never signed
anything, never spent. The only reason for the re-probe was
to capture the full 402 body — the previous census truncated
at 800 chars for storage economy.
For each full body we ran three validators in parallel:
-
Legacy v1 npm
[email protected]. We vendored[email protected](which re-exports the ZodPaymentRequirementsSchema) and[email protected]into a sandboxed Node project, piped each body throughPaymentRequirementsSchema.safeParse, and recorded success or the first few Zod issues. -
v2-aware npm
@x402/[email protected]/@x402/[email protected]. We installed those exact pins into an isolated Node project at.cc-agent/scratch/0974-v2-client/, importedPaymentRequirementsSchema(the v1∪v2 union exposed by@x402/core/schemas) andparsePaymentRequired(the top-level discriminated union), and ran every body through both: per-accepts-entry (equivalent to the v1 methodology) and top-level (what a v2-aware buyer would call to sanity-check the whole 402 body). -
Python
x402==2.25.0. We ranx402.schemas.parse_payment_requiredagainst each body. This is the parser the x402 facilitator stack uses on the receive side, intentionally more lenient about aliases and legacy slugs.
Everything happens offline from the three 402 bodies — no
wallet, no viem, no RPC. Raw dataset:
metrics/0970-x402-client-compat.json (v1 + python) and
metrics/0974-x402-fetch-v2-measure.json (v2, with cross-
tab against v1). Per-body v2 verdicts in
data/census/2026-10-12/x402-v2-parse-perbody.json.
The top failure buckets against v1, with fixes
Every number below counts endpoints — one row may contribute
to multiple buckets. “Fix” here means “what makes
a body parse under [email protected]” — i.e.
a fix for sellers still trying to serve v1-pinned buyers. The v2
story is different: see “What’s next” below.
1. v2-only shape — 175 endpoints (62% of 280)
These advertise "x402Version": 2. The v2 shape renames
maxAmountRequired to amount, drops the
required description/mimeType/resource
strings in favor of a nested resource object, and uses
CAIP-2 chain ids for network. The legacy v1 client
rejects v2 bodies before examining any inner field; the v2-aware
@x402/[email protected] accepts them.
Fix for sellers serving v1-pinned buyers: emit a
v1-shape fallback alongside v2 (key on an explicit
x-x402-client-version hint or inbound Accept).
Sellers who have moved on and have no v1 buyers in their traffic
can skip this.
2. Non-enum network strings — 175 endpoints (62%)
"network": "eip155:8453" (CAIP-2) and friends. The v1
enum is a closed set of 17 slugs: base,
base-sepolia, abstract,
abstract-testnet, avalanche,
avalanche-fuji, iotex, polygon,
polygon-amoy, peaq, story,
educhain, sei, sei-testnet,
skale-base-sepolia, solana,
solana-devnet. 30 distinct non-enum strings showed up
in the wild: eip155:8453, eip155:1,
eip155:56, solana:mainnet,
solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp,
xrpl:0, algorand:mainnet,
aptos:1, bip122:…, near:mainnet,
filecoin:mainnet, stacks:mainnet,
starknet:mainnet, stellar:pubnet,
sui:mainnet, ton:-239, arc,
x1, and more. v2 is CAIP-2 by design.
Fix for sellers serving v1-pinned buyers: use the
short slug where it exists. Example: emit
"network": "base", not "eip155:8453" and
not "base-mainnet".
// BEFORE (rejected by [email protected]):
"network": "eip155:8453"
// AFTER (parses):
"network": "base"
3. Missing required v1 fields — up to 151 endpoints each (54%)
description, mimeType, resource,
maxAmountRequired are all required strings in the v1
Zod schema. Many v1-shape bodies omit them when the server already
echoes the info in a sibling resource object or in the
extra block. v2 does not require these top-level
strings.
Fix for sellers serving v1-pinned buyers: populate
the fields even when redundant. A one-word
"description": "Paid x402 call." and
"mimeType": "application/json" clear the parser.
4. Numeric amounts — 19 endpoints
"amount": 50000 instead of
"maxAmountRequired": "50000". The v1 Zod schema
requires a stringified non-negative integer; a native number is
rejected.
5. outputSchema: null — 1 endpoint
Only one seller is still shipping outputSchema: null
in the sample. The field is ZodOptional<ZodRecord>,
so when there is no response-shape commitment, omit the key
entirely rather than null it.
We hit the same bug ourselves
One honest finding worth stating up front: on 2026-10-11 our own
/v1/intel/* paywall’s 402 challenge was
unparseable by [email protected]. We were emitting
network: "base-mainnet" (one of the 30 non-enum
strings above) and outputSchema: null. Any
v1-pinned buyer that hit us failed at parse time, before any wallet
action. We saw real traffic bounce off this shape (task 0959).
The fix landed 2026-10-12 (task 0960): emit "base"
(keep "base-mainnet" as an inbound alias so pre-fix
cached clients still settle), omit the outputSchema
key when there is no response-shape commitment, split outbound v1
networks into a smaller set than the inbound alias map. The site
ships a vendored Python port of the exact same v1 Zod schema as a
regression ratchet so a future accidental re-add of either shape
fails pytest locally and in CI.
We publish this census because a v1-pinned buyer is held to exactly the same bar — and because we were held to the same bar every outside seller is held to in the pre-fix days. 17.5% is a story about the subset of the ecosystem still pinned to v1; it is also a story about our own paywall one day ago.
Caveats worth stating out loud
-
v1 is a frozen artefact. We tested against
[email protected], last published 2026-04-16. Six months of ecosystem change happened after that cut. Treat the 17.5% number as “parse rate for anyone still pinned to v1 on 2026-10-12” — not “parse rate for a current stock npm buyer.” -
The v2-aware npm client ships today, and we measured it.
@x402/[email protected]and@x402/[email protected]went live 2026-09-29. The measured v2 parse rate across the full 280-body dataset is 249 / 280 (88.9%) at the per-accepts-entry level and 228 / 280 (81.4%) at the top-level discriminated union. The 21-body gap between those two numbers is bodies whoseaccepts[]entries each parse but whose top-level body is missing the v2resourceResourceInfoSchema object. - Python looks lenient on purpose. The facilitator stack needs to resolve legacy aliases on the receive side so pre-fix cached buyers can still settle. The lenience is not a bug — it is the half of the pair that keeps old clients alive.
- No sellers named individually. This is a census, not a scoreboard.
- One moment in time. npm clients version. Zod schemas tighten and loosen. 17.5% against v1 on 2026-10-12 does not predict 2026-11-12. The dataset JSON is dated.
The 31 bodies v2 still rejects, characterised
Measuring v2 lets us name every remaining failure. The 31 bodies break into three single-seller patterns:
-
14 endpoints — empty
assetstring in the 13th accepts entry (one seller). The seller ships 13 accepts entries per 402; the 13th has"asset": "". v2’sNonEmptyStringrejects ataccepts.12.asset. The other 12 entries parse cleanly — a one-character fix on the 13th entry would unlock the entire set. -
10 endpoints — no
acceptsarray / nox402Version(one seller). The seller returns HTTP 402 with a body that is neither v1 nor v2 shape — no discriminator, no accepts. Not strictly an x402 responder. - 7 endpoints — non-JSON body. The 402 response is HTML / plain text / empty. No parser can proceed.
That is the full accounting: 14 + 10 + 7 = 31. Two of the three patterns are single-seller bugs; a 50-second patch on either side closes most of the remaining gap.
For buyers
If you are still wiring a stock [email protected] into
an agent runtime today, assume the ERC-8004 paid surface delivers a
~1-in-6 parse rate out of the box. Upgrade to
@x402/[email protected] (published 2026-09-29) and the
measured rate climbs to 88.9% at the per-accepts-entry
level. Our free MCP server exposes a pre-flight
list_payable_x402_endpoints tool that returns only
sellers whose 402 bodies pass the v1 schema — call it before
you call settle. A v2-aware variant is on the roadmap
now that the measured v2 verdict exists per body.
What’s next
Three directions, in order of likely yield. First, surface the
v1×v2 cross-tab on-chain through the paid intel endpoints so
buyers can filter sellers by exact parse status without re-running
the schemas. Second, carry out the symmetric
parsePaymentPayload check on real X-PAYMENT headers
(requires paid settlement; separate task). Third, re-run this
census at a cadence — weekly on moving bodies, monthly on the
full set — so the parse-rate trajectory as sellers upgrade is
publicly observable rather than a one-off.
Reproducibility
Every numeral comes from a single re-probe pass on
2026-10-12, raw bodies retained. The vendored
[email protected] + [email protected] schemas, the
@x402/[email protected] / @x402/[email protected]
schemas, the python x402==2.25.0 parser, and both
collector scripts are in the repository; aggregate metrics live at
metrics/0970-x402-client-compat.json (v1 + python) and
metrics/0974-x402-fetch-v2-measure.json (v2 + cross-
tab). Per-body v2 verdicts are at
data/census/2026-10-12/x402-v2-parse-perbody.json; a
summary at
data/census/2026-10-12/x402-v2-parse-summary.md. No
methodology change was shipped as a result of this post.
Cite as
Onchain Agent Intel (2026). x402 client-compatibility census: 17.5% parse under v1, 88.9% under @x402/[email protected] — measured. Observational re-probe of 280 live 402 bodies on 84 ERC-8004 agents, 2026-10-12, against [email protected], @x402/[email protected] / @x402/[email protected], and python x402==2.25.0. CC BY 4.0. https://onchainagentintel.io/blog/x402-client-compatibility-census-2026-10