Dev.to WebDev ๐Ÿ›  Dev ๐Ÿ‘ 0 ๐Ÿ“– 5 min read

Your Listing Is a Snapshot, Not a Contract

This content reflects minia2a as of its publication date and is kept for the record. Current model: x402 pay-per-call in USDC on Base only, 5 free trial calls per signed wallet, no credits and no top-up rail. 2026-11-0

This content reflects minia2a as of its publication date and is kept for the record. Current model: x402 pay-per-call in USDC on Base only, 5 free trial calls per signed wallet, no credits and no top-up rail.

2026-11-09 ยท x402 operations

A buyer finds your endpoint in a discovery index. The index shows a price, a payee address, a
chain. Where did those three values come from, and how old are they?

For x402scan, the answer is specific: at registration. The self-serve
register call takes a URL, the index fetches your 402 once, parses the
accepts[] array, and stores it. Nothing re-probes that row afterwards. Your solution
can change price tomorrow and the index keeps advertising yesterday's number until you register
the same URL again.

We measured how much that matters for us. On 2026-11-09 we read the x402scan origin page for our
account, took every row on minia2a.uk, and probed each URL against the live challenge
to compare four things: the atomic amount, the payee, the rail (network + asset), and whether the
URL still answers 402 at all.

The population

measurement value
rows under minia2a.uk 1,123
snapshot age, median 0 days
snapshot age, max 65 days
rows older than 30 days 113
rows older than 45 days 70
accepts per row 1 (all 1,123)

Two things stand out. First, the median age is zero โ€” most of our rows were registered recently,
which is what a healthy self-serve flow looks like. Second, the tail is long: 113 rows were
snapshotted more than a month ago, 70 more than six weeks ago, the oldest 65 days.
Any of
those could have been advertising a price we no longer charge, and nothing in the index would say
so.

The result

verdict rows
identical to the live 402 1,122
price or payee drift 0
dead (no 402, no explanation) 0
retired (404 that names a replacement) 1
transient / unusable 0

Not one row was wrong. That is not luck: our 402 is computed per request from the live database,
so the challenge a probe sees today is the challenge a buyer pays today, and our prices have not
moved since those rows were registered. The stale snapshots are stale in date only โ€” the
values inside them still agree with the server.

That is exactly the shape of a latent bug. The mechanism that would publish a wrong price exists;
it simply has not fired yet, because nobody changed a price. The next price change makes 113 rows
lie simultaneously, and the only notice will be a buyer complaining about a charge it did not
expect.

The one dead row

https://minia2a.uk/x402/language-detect returns 404. We delisted that service
because it answered "english" for every Latin-script language โ€” French, German,
Spanish, Italian and Portuguese all came back English after a confident-looking detection pass.

A 404 is a fine answer to a probe. It is a terrible answer to a buyer, because the buyer
arrived from a listing that promised a service. So the 404 body carries the explanation and the
replacement:

{
  "delisted": true,
  "error": "Service not found",
  "id": "language-detect",
  "hint": "language-detect delisted โ€” it answered \"english\" for every
           Latin-script language ... Use x402-ai-language, which is correct
           for those and also returns the script."
}

Whoever follows that dead row lands on a live endpoint that does the job. That is the difference
between a dead link and a redirect: the row stays dead, but the journey does not. If you
delist a listed endpoint and your 404 is a bare page, you have converted an index into a maze.

The trap in checking whether you are listed

x402scan writes rows through two paths, and they land in different buckets:

  • self-serve register writes method: ""
  • discovery (from your openapi.json) writes method: "GET" or "POST"

The registration check is keyed on (url, method). So asking "is this URL
registered?" with one method and calling it a day under-reports โ€” and under-reporting is the
direction that makes you register everything a second time.

Our own measurements of the same account, on the same day, across three methods:

query registered
GET only 29 of 105
GET + POST 16 of 132
GET + POST + "" 89 of 132

The first two numbers were both wrong, and the second was lower than the first despite
asking about more endpoints โ€” a bigger population with an incomplete union. Today, over our 144
demand-backed endpoints (286 candidate URLs), the union is complete: 144 registered, 0 missing, with
the buckets at ""=132, GET=94, POST=94.

What we did not do

1,123 of our 1,856 catalog services are in that index; 733 are not. Some of the 733 have never
taken a single call. We did not mass-register them. An index gets less useful every time it gains a
row nobody searches for, and a provider that floods one to raise a number is optimizing the
provider's graph, not the buyer's. Discovery is a shared resource; spam spends it.

Limits of this audit

  • One index, one provider, one day. x402scan stores registration snapshots; CDP's Bazaar files a row from the payment payload at settle time, so its rows are settle snapshots with a different freshness mechanism and a different failure mode.
  • The live probe is an unpaid GET. It proves the challenge โ€” price, payee, chain, liveness โ€” is current. It does not prove a payment settles, and it does not test delivery.
  • lastUpdated is when the row was registered, not when it was last verified. A fresh date is not evidence the row was re-read.
  • Snapshot age and correctness are independent. All 113 stale rows happened to be correct. That is a fact about our changelog, not a property of the index.

The rule

A listing is a photograph of your 402 taken by someone else. The 402 is the contract.
If you cannot make the index notice that the contract changed, you owe it โ€” and your buyers โ€” a
scheduled re-read of the photograph.

The practical version, for anyone running a pay-per-call endpoint: register the same URL again to
force a re-probe, do it after any price or payee change, and audit the rows you already have on the
same schedule you audit your own documentation. And make sure a dead row points somewhere alive โ€”
the index will keep the dead link for as long as it likes.

Originally published at minia2a.uk.

๐Ÿ“ฐ Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.