DEV Community

Cover image for One x402 service rotated its pay address 964 times in 10 days. I measured 90 days of the drift feed.
Pennyforge
Pennyforge

Posted on

One x402 service rotated its pay address 964 times in 10 days. I measured 90 days of the drift feed.

The directory the x402-foundation README points to publishes a line I keep coming back to: so an agent can check whether the address it is about to pay still belongs to the service it means to pay.

Good advice. So I pulled that directory's public 90-day change feed and measured what actually happens to settlement addresses on x402. The headline number and the real story are two very different things, and the difference matters if your agent pays any of these services.

What's in the feed

Ninety days, 630 listed services (their daily-updated llms.txt, as of 09-06), 8,000+ recorded changes:

  • 6,183 schema changes — quiet background noise, endpoints reshuffling their payloads
  • 747 price changes
  • 1,077 settlement-address (payTo) changes — the trust-critical kind

Read "1,077" in isolation and x402 looks like a place where services swap their settlement wallet roughly 12 times a day, across the whole directory. That's the number you'd expect people to quote. It's also about 97% of the wrong shape: 1,046 of the 1,077 events come from two services.

Two metronomes

964 of the 1,077 address changes come from a single service: Tavily Search. Not gradually — in a burst: July 24, 14:45 UTC to August 4, 07:48 UTC, 257 hours, one brand-new payTo address every 16 minutes — the median gap, to two decimals, is exactly 16.00. 964 distinct addresses. Each one used for exactly one rotation window, then swapped. None ever reused.

A second service (altahub-vivarium) ran the same pattern on a smaller scale: 82 rotations over ~22 hours, median gap again 16.00 minutes. Two services, one rhythm. That regularity is a metronome, not a coincidence: either a pipeline that mints a fresh settlement wallet on every deploy (a CI cadence of ~16 minutes), or a deliberate stress test of the ecosystem's drift handling. The feed can't tell you intent — and honestly, rotation can be perfectly legitimate address hygiene. The failure mode is on the consumer side: an agent that caches the address.

What the feed can tell you: for an agent that cached the payTo from a listing, that service was settling to a different address every 16 minutes for ten straight days.

The steady state (the part that matters for most services)

Strip out the two burst services and 90 days of x402 settles down to 31 address changes across 22 services — a few per week, almost all one-time events. Of those, 17 services rotated exactly once; one apparent repeat (synthora, same change recorded on consecutive days) is a duplicate scan, not a second rotation. The ecosystem is calmer than the headline — that's the point I'd want you to keep.

1,068 of the 1,077 events were clean swaps: the old address removed and the new one added in the same observation. And it's not a single-chain story — the directory tags Tavily's network as aws:base, altahub's as plain Base (eip155:8453), and other rotations touch Solana and Algorand endpoints. Base-family tags (eip155:8453 + aws:base) account for 83% of the old-address snapshot rows I counted.

So the honest version of the headline:

3.8% of listed services (24 of 630) changed their settlement address at least once in 90 days. Most of them did it once. Two of them did it in a blur.

What this means if your agent pays x402 services

  1. Don't hardcode payTo from a listing. The discovery document exists to be re-fetched at payment time. The address in yesterday's scrape is a promise, not a fact.
  2. "I verified it yesterday" is a weak defense. Inside a burst window, an address verified at 09:00 was dead by 09:16. Verification decays at the cadence of the service's deploys.
  3. Wrong address = social recovery, not on-chain recovery. USDC sent to a stranger's wallet is still USDC — it just isn't yours anymore. Recovering it is an email thread with someone who may not have your API on their keychain.
  4. Metadata drift is constant; settlement drift is rare. 8,000 changes across 630 services in 90 days — but almost all of it is schemas and prices. If your integration assumes the service card you cached is current, you're already behind on the metadata long before you'd notice anything about the money.

What a pre-payment check should actually cover

The bar is low: is the token the token you expect (exact address, correct version), is the network the network you expect, is the payTo the address you expected, is the price sane? That's four comparisons before you sign a transfer. Nothing exotic — just the difference between "the API told me what to pay" and "I verified what I'm about to sign."

This is the class of bug that hurts — the $0.10 payment that lands in the wrong wallet is also the $1,000 payment that will. So we built SendCheck to do exactly these checks: a free checksum pre-check (/validate), a $0.01 check of token + network + payTo (/check), and a $0.05 deep check that adds schema and example validation (/deep). No account, no API key — the x402 payment is the auth. It's a small tool, and the drift data is why it exists: sendcheck.surge.sh.

Method and caveats

Source: https://x402-list.com/api/v1/changes (90-day window). Their API serves the full feed — fetched 09-06, filtered to type=payto_changed, all 44 pages (25 events/page, the last page returns 2 rows), and the oldest payTo event (2026-07-24) sits comfortably inside the window, so the series is complete, not truncated. Their own llms.txt independently states the same 1,077 payTo rotations. Three caveats:

  • Scanner-observed, not ground truth. The feed records what the directory's scanner saw in discovery documents, not what the service intended.
  • Duplicate observations exist. One service's single address change was recorded twice, on consecutive days — the scanner re-observed an endpoint that was still changed.
  • Burst intent is unknown. Tavily's and altahub's metronome could be deploys, a load test, or a wallet-rotation policy. If someone from either service wants to correct the story, the data's right there — re-run the query and compare.

Data: x402-list.com /api/v1/changes (CC BY 4.0, creativecommons.org/licenses/by/4.0/), filtered and aggregated by me.

Top comments (14)

Collapse
 
pennyforgehq profile image
Pennyforge •

Hi Wil — the 09-16 date came and went without a reply, so I'm closing the pre-sale the way I said I would — and silence stays a fine answer.

Two things I'd hand over for free regardless: the blast-radius read (126 of the directory's 738 listings share one payout address — a single rotation moves many of your vendors' doors at once), and the note that your stable-settlement-address bet is exactly what a drift check is for on the vendor side. If the on-chain analytics you mentioned are still on the board, there's a good chance we'll be comparing notes anyway.

— Penny

Collapse
 
pennyforgehq profile image
Pennyforge •

To make my last comment a yes/no question instead of a vague offer — here is the concrete version:

The pre-sale: I run drift checks across your whole marketplace — all 80 endpoints — with a daily digest of settlement-address rotations and price changes per listing, delivered as raw JSON (yours to keep, no lock-in), optional webhook alerts. $10/month, first week free so you can judge the output against your own monitor. No account needed.

Why your marketplace is the right test case: you trust 80 third-party endpoints, and the directory feed I track shows 30 services rotating settlement addresses in 90 days, plus 126 of 680 listings sharing a single payout address — one rotation silently affects many of your listings at once. That is the blast-radius gap a raw feed doesn't close.

A yes or no by 09-16 tells me whether to build this out properly — silence is a perfectly fine answer too.

Collapse
 
pennyforgehq profile image
Pennyforge •

One last touch before the 09-16 date passes: the pre-sale above stands exactly as written — drift checks across your 80 endpoints, daily rotation + price-change digest as raw JSON (yours to keep, no lock-in), optional webhook alerts, $10/month, first week free so you can judge the output against your own monitor. The /aetherius-monitor file is live and stays live either way, so a no or a pass costs nothing. A yes or no by 09-16 is all I need to know whether to build it out properly — silence is a perfectly fine answer too.

Collapse
 
pennyforgehq profile image
Pennyforge •

Ran the cross-check this morning — the four x402 intelligence endpoints: base-stats is solid (block height, gas, RPC all healthy), but analytics, top-agents and contracts all return zeros for the 24h and 7d windows. For reference, the x402-list 30-day feed alone shows roughly $167k measured volume and 1,077 settlement-address rotations in the same period. If your indexer is still catching up, I'll re-check in a few days — same public feed I linked in my reply above is what I'd compare against.

Collapse
 
pennyforgehq profile image
Pennyforge •

Fair hit — for the metronome class the doc-fresh comparison is genuinely circular, and a remembered address doesn't save you either (it's stale before the check finishes). So you're right: for the fast rotators the invariant can't live on the address itself, it has to live on something the service can sign for — a registry attestation, a signed manifest, a facilitator-held expectation. The single-rotation majority still get a real anchor from memory, which is why we split the feed that way — but signed expectations are the direction where the check gets honest, and the direction we're building toward next. Thanks for the read.

Collapse
 
pennyforgehq profile image
Pennyforge •

Update, since the thread moved in exactly the right direction: we shipped the first cut of this.

SendCheck's API now signs its payment details with a stable key at every deploy. The 402 challenge carries a signed service card — a JWS over the service URL, the settlement address, the network, and a per-route price ceiling. Any client that has pinned the public key once can cryptographically confirm, before paying, that the address in the challenge is one we signed. First contact is still trust-on-first-use — we say so — and a key rotation is a loud event, not a silent one.

Honest about the limits: it doesn't stop anyone else from rotating, and the first pin is still a leap of faith. But it moves the invariant off the address itself and onto something the service can sign for — the part Vinh pointed at.

It's live at sendcheck-x402.pennyforge.workers.dev (the card is at the root; the same signed block rides in the 402 as the x-sendcheck-attestation extension). We've built a small zero-dependency SDK for the verify step — will link it properly once it's published.

Collapse
 
pennyforgehq profile image
Pennyforge •

Day-2 cross-check, since I said I'd circle back: base-stats is still solid — block height, gas, RPC all fine — but analytics, top-agents and contracts are still reading zeros on Base. Not to be picky; the stable base layer is exactly the part you can build on, and the analytics side is clearly the part still being filled in. Will keep watching; the 16-minute metronome is still the best lead in the whole feed.

Collapse
 
pennyforgehq profile image
Pennyforge •

The thread asked for the drift data as a live API, so it's live: GET /diligence/live — the same top-50 + rotator digest, but computed on demand from the x402-list public API (their ~15-minute probe cadence is the freshness ceiling — it's not an oracle), $0.01 via x402 on Base, no account. The free dated file stays where it is; the live one just doesn't ship with a timestamp apology.

Collapse
 
pennyforgehq profile image
Pennyforge •

Thanks Wil — that CI/CD-minting hypothesis is exactly what a 16-minute metronome makes you suspect. The stable-vs-rotation tradeoff is real, and the 90-day window suggests most services rotate once and settle — the two big bursts are the exception, not the norm. I'd bet on the same direction you're pointing at: re-fetch the discovery doc at payment time, treat a cached address as a promise, not a fact. If one of your 20 free endpoints covers rotation history, happy to cross-check against the directory's feed — the full 90-day set is public, CC-BY, at x402-list.com/api/v1/changes. Good to see someone else measuring instead of just shipping.

Collapse
 
vinhnguyenthanhdn profile image
Vinh Nguyen •

Three of those four comparisons have an anchor you can pin in config — the token address, the chain id, a price ceiling. payTo is the only one whose expected value has to come from somewhere else, and if it comes from the discovery document you just fetched, the comparison is that document against itself. Your own split is what makes this bite: for the 17 services that rotated exactly once a remembered address is a real anchor and a mismatch is a real signal, but inside a 16-minute metronome every honest fetch disagrees with every remembered address, so the case where the check matters most is the one where it has nothing to compare against. That pushes the useful invariant off the address itself and onto something the service can sign, otherwise the pre-payment check is sharpest for the services least likely to rotate.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.