← All posts

x402 client-compatibility census: 17.5% parse under v1, 88.9% under @x402/[email protected] — measured.

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

ValidatorParses%Status
Legacy v1 npm [email protected] Zod schema (vendored, last published 2026-04-16)49 / 28017.5%Frozen; six months since last release
v2-aware npm @x402/[email protected] / @x402/[email protected] — per-accepts-entry PaymentRequirementsSchema union249 / 28088.9%Current; shipped 2026-09-29
Same v2 client — top-level parsePaymentRequired discriminated union (also enforces top-level resource for v2)228 / 28081.4%Stricter than per-entry
Python x402==2.25.0 parse_payment_required262 / 28093.6%Current; lenient facilitator-side parser
v1 pass & v2 pass (both v1-pinned and v2 buyers can parse)49 / 28017.5%v1 is a strict subset of v2
v1 reject & v2 pass (upgrading v1-pinned buyer unlocks)200 / 28071.4%The “upgrade-and-you-get-this” delta
v1 reject & v2 reject (unparseable in either npm runtime)31 / 28011.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.0 at the time still sits here today.
  • Current v2 line: @x402/[email protected] and @x402/[email protected], published 2026-09-29. @x402/core exposes PaymentRequirementsV1Schema, PaymentRequirementsV2Schema, and a union PaymentRequirementsSchema that 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:

  1. Legacy v1 npm [email protected]. We vendored [email protected] (which re-exports the Zod PaymentRequirementsSchema) and [email protected] into a sandboxed Node project, piped each body through PaymentRequirementsSchema.safeParse, and recorded success or the first few Zod issues.
  2. 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/, imported PaymentRequirementsSchema (the v1∪v2 union exposed by @x402/core/schemas) and parsePaymentRequired (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).
  3. Python x402==2.25.0. We ran x402.schemas.parse_payment_required against 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 whose accepts[] entries each parse but whose top-level body is missing the v2 resource ResourceInfoSchema 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 asset string in the 13th accepts entry (one seller). The seller ships 13 accepts entries per 402; the 13th has "asset": "". v2’s NonEmptyString rejects at accepts.12.asset. The other 12 entries parse cleanly — a one-character fix on the 13th entry would unlock the entire set.
  • 10 endpoints — no accepts array / no x402Version (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