SWARM · by SWARM's operator · published 28 Oct 2026

Series: part 1: what broke our 402, and how we fixed it · part 2: putting a paid API behind an MCP server · part 3: miscounted buyers, and an API key that expired quietly · part 4: one payment, five deliveries, and first buyers that were robots · part 5 (this page) · all articles

x402 seller gotchas, part 5: a price list that lied, free RPCs that ran out, and an agent that said "full scan"

In part 1 we listed what broke while selling small services over x402 (pay per request, USDC on Base), and in part 4 we found that our first buyers were robots. This week was less about buyers and more about our own tools telling us things that were not true: a price list, a data source, and our own AI agent. Seven gotchas.

The lesson that matters most: anything that reports a result (a file, a script, an agent) needs a way to show how much it actually checked.

The price list that lied#

Our 402 said our report cost $0.99. Two static files on our site (agent-card.json and x402.json) still said $2.00. Nobody had updated them after a price change, and nothing compared them. This is point 6 of Payload's "x402 in production: the failure modes nobody warns you about", and we had it.

There was a second copy of the old price: Coinbase's catalog. It only refreshes a listing when someone pays for that service. A new description stays invisible until the next purchase. On 20 Oct we made a test purchase to force it, and by 22 Oct the new descriptions were showing.

Fix: our morning report now compares the live 402 of every paid route with every static file that mentions a price, every day. If a price changes, buy once from yourself so the catalog picks it up.

Reading many wallets burns the free sources#

To tell real buyers from sweepers, we started reading the payment history of many wallets on Base. In two days we ran out of free data:

It took us 8 scripts to get something stable: read forward, once an hour, from now on, and stop trying to rebuild the past.

Fix: start slow, measure forward, and keep a log of what each free source allows before you depend on it. Also read its terms. Some data APIs don't allow storing or sharing what you read, even when the endpoint is open.

"Confirmed with a full scan"#

Our agent told us Coinbase had removed us from its catalog, "confirmed by a full paginated scan (3 pages, 3000 items)". It even had an explanation that "lines up to the day": no real payment for 30 days. The catalog had 36,218 listings. Ours were at positions 6,541 to 7,743, and the 30-day clock counts any settled payment, tests included. It then built a small watcher script that read at most 5,000 listings, and it "confirmed" the removal again. Our morning summary forwarded the claim to us as it was. Later that week it repeated the claim after reading about 1,200 entries.

Fix: a receipt rule (the idea came from clawlogan on Moltbook). Any claim of "all", "none" or "full scan" must come with the count read and the total available, for example "read 3,000 of 36,218". Without the numbers, the claim doesn't count. What the agent says is not data until we check it.

We shared the rule in public, and a developer who builds an MCP search tool took it further. When a tool finds nothing, there are three different answers, and they should never look the same:

  1. The search didn't finish (timeout, 429, network error): UNKNOWN, never "searched".
  2. The thing isn't in the index yet, or is newer than the index: "not indexed", look elsewhere.
  3. The search reached real data, says how much and how fresh, and found 0 matches: "searched, none".

Adding one field, when the data was last checked, makes the difference automatic. "Nothing found" has to say whether it really looked, in what, and how old that data is.

The job that lived in the agent's memory#

We gave our agent one fixed weekly job: write the list of payment failures for this article. The first week it didn't do it. It spent its daily budget before 18:00, and the job was written only in its diary notes, which its own clean-up archives.

Fix: the job is now a fixed task file it does first, at 00:00 UTC on Wednesdays, before anything else. Anything that must happen can't live only in an agent's working memory.

A related one: the agent wrote one of our prices wrong ($0.02 instead of $0.002), even after we corrected it with a note. A note is not a fix. Since 23 Oct it reads the price from the live 402 instead of remembering it. (The second wrong price we saw that week was not the agent: our own watcher was reading an old report. Same lesson.)

Talking to your own agent is harder than it looks#

We added a private chat from our phone to the agent and asked it one question. It never answered, and it marked the question as "covered" by its usual task. We found four bugs in a chain:

  1. The chat budget closed as soon as the agent picked up the message, so an hourly cap stopped it before it replied. Now the budget stays open until it answers.
  2. When it woke up, the first loop only read the wake-up text, and the inbox was read in the second loop. If the first loop decided to sleep for 7 hours, the message waited unread. Now the inbox is read in the first loop, and it can't sleep with an owner message unanswered.
  3. If a cap stopped it after picking up the message but before thinking, the message stayed "in progress" forever. Only "received" messages were picked up again. Now owner messages stuck "in progress" are picked up again, up to 3 tries.
  4. While the message was stuck, the code thought the owner was still waiting and charged 43 cents of the agent's own work to the chat budget. We moved it back.

On top of that, in its replies the agent said we had "30 real sales". They were 30 payments: 25 of our own tests and 5 inspectors.

Fix: test the whole path (message, wake-up, read, reply) with your caps switched on, and make sure a message can't stay half-done without anyone seeing it.

A payment that failed because the wallet had code#

On 23 Oct someone used our own npm package (User-Agent "swarm-x402-mcp/0.1.3") to ask for prices and try to pay two of our routes. Coinbase's facilitator rejected both payments with a strange error: "invalid_exact_evm_payload_signature: failed to unpack result: abi: attempting to unmarshal an empty string while arguments are expected".

We looked at the wallet. It was an EIP-7702 account: a normal wallet that has delegated to a contract. It had thousands of transactions sent, 0 USDC, and it paid none of the sellers we track. Almost certainly a program testing sellers with an empty wallet, not a buyer.

What we think happened (our best reading, not confirmed): when the paying wallet has code, USDC doesn't check the signature the normal way. It asks the wallet's contract (ERC-1271). If the delegated contract doesn't answer that question, the payment fails with this odd error even if the signature is fine.

Fix, for sellers: that error doesn't mean "a probe sent a bad signature". It can mean "this wallet has code". Check eth_getCode for the payer before you label it as a probe or a customer. For buyers: an EIP-7702 account may not be able to pay x402 "exact", depending on the contract it delegates to. And a User-Agent with your own package's name doesn't make someone a customer.

A 200 that looks like free#

This week we checked the 402s of a dozen other x402 sellers from the outside, without paying. One endpoint answered a GET with 200 and a JSON description of itself. The same URL with POST answered a correct 402. A monitor that only sends GET would report that paid tool as free, or as broken.

Fix, for sellers: answer the wrong method with 405, or with the same 402. For anyone checking sellers: use the method in the seller's docs, and treat a 200 without a 402 as "not checked" until you try it.

Where it stands#

Customer sales are still zero. Everything outside that paid us so far has been a sweeper, a probe or an inspector. Failed payment attempts fell from 11 the week before to 3 this week, all from probes.

Sell with x402? New from us: we'll watch up to 10 of your paid endpoints for 30 days. You tell us the price and payTo each should have; we check within 72 h of payment, then every 6 h for 30 days, and message you within 24 h if a 402 breaks or stops asking for what you set. 15 USDC upfront, no keys, no automatic renewal, no guarantee of sales. Today the checks are done by hand; the 6-hourly script is written when the first customer pays. Nobody has bought it yet. Open until 14 November. Comment or write to contact@swarm-agent.net.

The shop: swarm-agent.net · SWARM's MCP server · machine-readable: openapi.json · .well-known/x402 · found a mistake, or a gotcha we missed? contact@swarm-agent.net