x402 and sellers · November 2026

When an AI agent decides not to pay, the seller never hears why

Frits Zwager, Fizzl · numbers from the x402 Trust Index scan of 31 October 2026 (42,073 x402 endpoints checked) and the reasons in the scan of 1 November

More and more AI agents and wallets check an x402 endpoint before they pay it: is the price within the budget, is the payout address the one it was yesterday, can this wallet pay on that network at all? When the answer is no, the agent simply doesn't pay. The seller sees a 402 go out and nothing come back. From the seller's side, a refused offer looks exactly like a client that went away, so they can't tell "my price is above common limits" from "my payout address changed and wallets stopped trusting it" from "my challenge is broken".

1 in 12x402 endpoints got "careful" or "don't pay" from a pre-payment check (3,478 of 42,073 on 31 Oct)
0standard ways in x402 today for a buyer to tell the seller why it didn't pay
12reason codes in the draft refusal extension, plus "other"
0fields about the buyer in a refusal report

Why buyers stop

x402 Doctor runs the same checks an agent runs before it pays, on every endpoint in the x402 Trust Index, every day. These are the most common reasons a check gave in the scan of 1 November for a 402 a buyer could have paid, next to the refusal reason a buyer would send. (Endpoints that were down or answered no 402 are left out: there was nothing to refuse.)

What the check foundEndpointsRefusal reason
Only Circle Gateway, which standard x402 clients can't pay1,651network_unsupported
The 402 names another resource than the URL that was asked707terms_mismatch
A token that is not a known stablecoin176asset_unsupported
Testnet only160network_unsupported
The 402 asks more than the price the seller advertises83terms_mismatch
An invalid challenge16challenge_invalid
A very high or suspicious amount24policy_blocked
No option the buyer can pay13network_unsupported

Real buyers add their own reasons on top: a spend limit per payment (price_above_limit), a payout address that changed since last time (payto_changed), a sanctions hit (screening_hit). Every one of these is something a seller can fix, if they hear about it.

How the refusal extension works

We proposed it as an open x402 extension, x402-foundation/x402#4087, so any wallet can send it and any seller can read it. Two steps:

1. The seller says where refusals go. One small entry in the 402's extensions:

"refusal": { "info": { "url": "https://seller.example/.well-known/x402-refusal", "version": "0.1-draft" } }

2. A buyer that doesn't pay posts a short report there, and doesn't wait for the answer:

{ "x402Version": 2, "resource": "https://seller.example/api/weather", "offer": { "hash": "<sha256 of the refused accepts[] entry>", "acceptIndex": 0 }, "reason": "price_above_limit", "detail": "limit $0.05, asked $0.25", "checkedAt": "2026-11-01T08:00:00Z" }

The offer hash is the sha256 of the refused accepts[] entry in canonical JSON (keys sorted, no spaces). The seller can tie the refusal to the exact terms it showed, without the buyer sending them back. The resource goes without its query string, so none of the buyer's input travels with it.

Protected against the obvious abuse

Add it to your endpoint

In Express it is the extension entry in each paid route plus one small route:

app.post("/.well-known/x402-refusal", express.json({ limit: "4kb" }), (req, res) => { console.log("refusal", req.body?.reason, req.body?.resource); res.status(204).end(); });

Then run x402 Doctor's free check on your endpoint: it now says whether your 402 takes refusals, whether buyers would send to your url, and whether it answers. A full implementation of both sides (reason codes, offer hash, a seller endpoint with optional signature checks and counts) is open source in x402 Doctor's lib/refusal.js.

Who already uses it

It is a draft. Comments on the issue are very welcome, especially from sellers on which reason codes they would want.

How we counted

Questions

What is the x402 refusal extension?

A draft x402 extension (x402-foundation/x402#4087). The seller's 402 names a refusal url on its own site; a buyer that decides not to pay posts a short report there: a reason code from a fixed list, the sha256 of the refused accepts[] entry, the resource without its query, and the time. Nothing is paid and nothing about the buyer is sent.

Can a competitor flood a seller with fake refusals?

Buyers only send to a url on the seller's own site, at most once a day per resource and reason, and sellers rate-limit the endpoint. Unsigned reports are hints that a seller should never act on automatically; a report signed by a wallet (EIP-191) shows a real wallet sent it.

How do I add it to my x402 endpoint?

Add extensions.refusal = { info: { url: "https://<your host>/.well-known/x402-refusal", version: "0.1-draft" } } to each paid route and answer POSTed reports there with 204. x402 Doctor's free check tells you whether it works.

Check your endpoint with x402 Doctor, check a payment before signing with presign-guard, and let an agent buy safely with the Fizzl Agent Wallet.