2026-10-31 ยท field note
We published a new endpoint at $0.15 per call. It answered its 402 correctly. Every caller who tried to pay it failed, and the service earned nothing until we found the cause: its description was 509 characters long.
The error, verbatim, from the facilitator:
'paymentPayload' is invalid: must match one of [x402V2PaymentPayload, x402V1PaymentPayload]
That message names a schema. It does not name a length. Nothing in it suggests that the thing to shorten is the prose you wrote for a directory listing.
The x402 challenge is a document, and the description lives inside it:
{
"resource": {
"url": "https://minia2a.uk/x402/...",
"description": "<the text you wrote for humans>"
},
"accepts": [ { "scheme": "exact", "network": "eip155:8453", ... } ]
}
A client that reads the challenge and decides to pay copies that document into the payment payload it forwards to the facilitator. So the seller's marketing copy becomes part of a structure that a third party validates. Our copy is not in that payload because payments need it โ it is there because the challenge carries it and the client does not strip it.
Which means the constraint is not ours to see. We can validate our own 402 all day: it is a perfectly conforming challenge. The rejection happens one hop later, at settlement, on a document we composed but do not validate.
Bisecting description length on that endpoint, holding everything else fixed:
| description length | result |
|---|---|
| 270 chars | settles |
| 418 chars | settles |
| 450 chars | settles |
| 509 chars | rejected โ paymentPayload is invalid |
The boundary is somewhere in (450, 509]. We did not pin it, and we are not
going to pretend the number is a spec constant: it is a black-box measurement against one
facilitator, and the real constraint may be a total payload budget rather than a
description-specific limit. If it is a total budget, then the headroom depends on the other
fields in accepts[] โ the payTo address, the network string, the asset, whatever
extensions the seller adds โ and any fixed character cap is a proxy that happens to be safe
for our shape.
We set the operational cap at 480 characters, inside the measured window, and applied it to every surface that serves a 402.
Our catalog, measured after the fix (1,685 first-party rows):
| metric | value |
|---|---|
| median description | 103 chars |
| rows at or over 400 | 7 |
| rows at or over 450 | 3 |
| longest (x402-ai-audit) | 470 chars |
The first sweep found four self-run services over the line โ 699, 515, 493 and 485
characters โ all written in good faith, all improving their directory listing, all
unpayable at the same time. They now sit at 226โ239 characters. The live 402 for
/x402/ai-audit today carries its 470-character description in a 3,980-byte
PAYMENT-REQUIRED header, with the accepts entry itself weighing
250 bytes โ the description is most of the document and none of the payment terms.
Consider what a seller sees when this happens:
From the outside this is indistinguishable from "nobody wants to buy". The listing looks healthy. The 402 looks healthy. The only signal is an error string that points at the wrong object. A service can sit in that state indefinitely, because the thing that would reveal it โ a successful payment โ is exactly what is blocked.
This is the same family as the bugs we keep finding in our own handlers: a caller mistake that returns a confident, well-formed answer. Here the platform returns a confident, well-formed challenge for a service that cannot be paid.
The check went into the guard that already reads resource.description on every
surface we serve, rather than becoming a second, narrower tool:
MAX_DESC_CHARS = 480, judged after the existence checks, so a
900-character placeholder is still reported as a placeholder rather than a length
problem.We also checked that the catalog text is the same text the 402 serves, so the exhaustive axis judges the document that ends up in the payload rather than a copy of it. For the two longest rows the two surfaces were byte-identical.
One caveat worth stating plainly: we have a measured window and an operational cap, not a published limit. If the real constraint is the total payload, then a seller with longer addresses or extra fields has less room than we do, and 480 is our number, not a rule.
minia2a is an x402 marketplace: 1,685 first-party pay-per-call endpoints in USDC on Base, five trial calls per signed wallet, no registration. The numbers above were measured on 2026-10-31 against the live catalog and live 402 responses.