Public register · updated 11 Oct 2026

Which agent-payment code pays once when the answer is lost?

A payment settles. The connection drops before the reply. Most code reads that as "failed" and pays again — and every replay guard correctly lets the second payment through, because it is a genuinely new one. This register records, with public evidence, which implementations survive that moment.

"Could not determine" is a terminal answer. It is never "did not happen."The rule every verdict below is measured against. It is §4.3 of a retry-safety proposal we co-authored for MCP (a working draft with no sponsor yet, not an adopted standard) and the receiver obligation we argued for in the x402 settlement-status thread.

The rail, measured

Before grading anyone we counted who is actually there. Every host on the two public x402 directories was asked GET /supported — the one endpoint every facilitator must answer. No payment, no key, no account. Swept 3 Sep 2026.

442hosts on the public x402 lists
11live facilitators answering /supported
7declare exact on a public testnet
2of the 11 carry an open double-charge finding of ours, with a runnable red test

A first probe run against all seven was refused by every one of them, for five different reasons (unregistered payee, unsupported scheme, invalid payload, unauthorized, bad signature) — which measures our request format, not their safety, so no grades are published from it. Declaring a scheme is not the same as accepting a stranger’s payment; each facilitator’s own requirements have to be read and met before any verdict is possible. Most of the 442 are sellers, not facilitators — one facilitator settles for many. Eleven is the size of the layer that decides whether an agent pays once. The two with open findings are counted, not named, until they ship; the probe that produced the finding is public (hostile_client.py), so any of the eleven can run it on themselves first.

The ledger

Named on this page? Show it: README badges. Every row links to its proof. Open findings are counted, never named — a company is not put next to a bug until they have fixed it. Fixed entries are listed with credit, because shipping a fix in hours is the thing worth recording.

6verified safe
14found & fixed — payment paths
4.3hfastest fix, report to release
21open, under disclosure (unnamed)

New, 4 Sep: The code is right, the sentence charges twice — eight agent-payment toolkits from card processors and billing platforms, read for one failure. Five can charge twice; in three of those the idempotency mechanism is correct and the description handed to the model defeats it. Three were clean and are named.

Earlier: Seven in ten pay twice — the field study behind this ledger: ten money paths read in three days, the seven shapes the defect takes, and what the safe ones do differently.

ImplementationVerdictWhat was at stakeEvidenceTime to fix
x402 reference implementation
x402-foundation/x402 · TypeScript, Go, Python
VERIFIED SAFE
by battery run
Reference facilitator & resource server for the whole ecosystemLive probe, Base Sepolia, 3 Sep 2026. One signed EIP-3009 authorization presented twice to /facilitator/settle: settled exactly once (0x28d59010…, block 46362866, status success), and the re-presentation was answered invalid_exact_evm_nonce_already_used — which states the authorization was consumed, so a payer cannot mistake it for "never settled" and re-sign. Caveat, stated: that answer carries no transaction hash, so it cannot be reconciled from alone. Earlier code read (PR #3083) now confirmed by measurement.

Seller + buyer, end to end, 5 Oct 2026. The official kits, unmodified, run through all ten modes of hostile-facilitator 0.2.2: Python x402 2.25.0 (FastAPI seller, httpx buyer); TypeScript @x402/fetch → @x402/express and @x402/hono 2.28.0; legacy v1 x402-fetch → x402-express 1.2.0. Every mode the run reached settled exactly once for one purchase; the buyer never signed a second authorization. The four reconcile modes were not reached — the SDK has no "did it land?" read — and are not counted. Caveat, stated: v1 has no facilitator timeout, so its seller waited out the timeout mode instead of timing out. Harnesses: examples/.
—
Stellar facilitator
accensa/x402-facilitator-stellar
VERIFIED SAFE
by code read
Facilitator on the Stellar railRetries only pre-response failures; never fast-fails a live sendTransaction (src/rpc-retry.js). Read 1 Sep 2026.—
x402-rs
x402-rs/x402-rs · Rust: x402-axum seller, x402-reqwest buyer
VERIFIED SAFE
by battery run
Rust seller middleware and payer, both sides of the purchaseRun 5 Oct 2026, x402-axum + x402-reqwest 2.0.2 unmodified, ten modes of hostile-facilitator 0.2.2: one settlement per purchase in every mode reached. The payer signs once per request and returns whatever the paid retry gets, never a second authorization (x402-reqwest/src/client.rs). Not reached, not counted: the four reconcile modes (no "did it land?" read).—
thirdweb x402 payer
thirdweb-dev/js · thirdweb/x402 wrapFetchWithPayment
VERIFIED SAFE
by battery run
Agent and app payer in the thirdweb SDKRun 5 Oct 2026, thirdweb 5.121.6 paying the official @x402/express 2.28.0 seller through all ten modes: one settlement per purchase in every mode reached. A paid request answered 402 is returned, not re-paid; a nested retry throws "Payment already attempted" (fetchWithPayment.ts). Payer side only; reconcile modes not reached, not counted.—
Agent Press Wire MCP
dylancaponi/agent-press-wire-mcp · x402 payer over @x402/fetch 2.28.0
VERIFIED SAFE
by code read
An MCP tool that spends real USDC on Base from the user's own wallet, called by an agentRead 8 Oct 2026 at 19beb98. Nothing re-signs on its own: there is no retry loop, and every payment needs a single-use confirm token bound to the endpoint, the exact parameters and the price (index.ts:191). The signed authorization is written to a persistent ledger under a lock before it is sent (index.ts:208), and every signed authorization counts toward the lifetime cap whatever the HTTP outcome, because the seller can still settle it until validBefore (guard.ts:154). A lost answer is reported as "settlement status is unknown", never as failed (index.ts:255). Defaults to quote only. Ceiling: a code read, not a battery run; the "did it land?" check is left to the user's wallet rather than read from the token contract.—
PipRail SDK
piprail/piprail · multi-chain agent payer + gate
VERIFIED SAFE
by code read
Payer that submits signed authorizations and on-chain proofs across railsOn a timeout after submitting the authorization it surfaces the nonce and instructs "re-present the SAME signed authorization; do NOT re-pay"; a 402 without success:false re-presents the same header; spend is recorded exactly once on the affirmative-settle path (sdk/src/client.ts). Read 3 Sep 2026.—
Trigger.dev
triggerdotdev/trigger.dev · background jobs platform
FIXED
documentation defect
The idempotency docs listed “Avoiding double-charging customers — Prevent duplicate payment processing during retries” as a use case. Idempotency keys deduplicate trigger() calls; they do not protect a payment call made directly inside run(), which re-executes from the top on every retry. An operator reading that line could reasonably believe a charge inside a task was covered when it was not.#4627 → PR #4952 (merged 18 Sep 2026) and PR #4953. The claim was rewritten and a new Side effects inside run() section added, stating plainly that an idempotency key “stops a task from being triggered twice. It does not stop the code inside that task from running twice,” and that only the provider can deduplicate its own API call. The behaviour was independently reproduced on the thread by an outside contributor before the fix. Stated plainly: the defect was the documented claim, not the runtime — Trigger.dev’s idempotency keys always worked as designed at the trigger boundary.34 d
ClawRouter
BlockRunAI · LLM router, USDC per call
FIXEDPre-auth catch spanned the payment-carrying send; a lost response signed a second payment#317 → released v0.12.267 with a red-green test that makes the send reject4.3 h
Altana SDK
altananetwork · x402 merchant server + wallet
FIXEDA receipt read that failed after a successful broadcast was answered as "settlement failed" with a fresh challenge, so the buyer signed a second authorization and paid twice#76 → PR #77: settle now returns settlement: "pending" with the hash instead of throwing, and the replay guard reconciles a re-presented authorization against that hash. Reproduced on an anvil BNB-mainnet fork before the fix (one purchase, 0.4 $U collected at a 0.2 price, both transactions status=success); their review found a second instance of the same defect on the broadcast path and fixed that too.6.2 h
Agent402
MikeyPetrillo · agent purchase client
FIXEDDefault idempotency key was clock-seeded, so an agent-level retry re-debited credits#1126 → agent402-client 0.8.3, key now stable across calls16.5 h
x402 MCP bridge
hpp-io
FIXEDWallet daily-spend cap could be exceeded by concurrent payments#1018 h
hypawave MCP
hypawave · Lightning payments
FIXED
documentation defect
The documented spending cap read as a budget; it is a per-payment size bound. The maintainer showed cumulative spend was already bounded at the wallet through the NWC connection budget, so the defect was the wording, not the spend path. Corrected here on 8 Sep after re-reading their close; the earlier wording of this row implied a spend bug.#1 → wording fixed in 0.4.126 h
Franklin
BlockRunAI · agent wallet
FIXEDWallet reservation released on an aborted x402 payment that could still settle#1289 d
sol-x402-facilitator
dchu3 · Solana x402 facilitator (deployed)
FIXED
evidence no longer public
Pending settlements were pruned at 60 min while the reconciler could not rule until 120 min, so a retry inside that window found no pending row and settled again; their 2 Sep production rate-limit incident was this defect live#9 → PR #10, merged and deployed with regression tests reproducing both orderings; the maintainer confirmed their 2 Sep production incident matched defect 2. The repository was taken private on or before 7 Sep and no public archive exists, so a reader can no longer check this row at source. It rests on our dated log of the thread (filed 3 Sep, fix confirmed 5 Sep) and is labelled accordingly rather than removed.41.4 h
resolve402-mcp
charleskremer-hub/resolve402-mcp · x402 payer for French company data (Base, Solana)
FIXEDA paid call answered 402 after the signed payment was sent was reported to the model as “Payment refused … Nothing charged”, though a seller can answer 402 after the transfer has already settled; a lost connection after paying surfaced as a raw error. Either way the natural next step was a second paid call.#1 → released in resolve402-mcp 0.3.1: both cases now answer “payment not confirmed” with the amount and payTo, and tell the agent not to retry before checking the wallet.40 h
Tebra MCP server
jamesrosing/tebra-mcp-server · healthcare practice management, patient payments
FIXEDtebra_create_payment retried on a timeout with no idempotency key and no server-side dedup, so an ambiguous outcome could post a second patient payment#13 → PR #18 (0.5.1, on npm): every Create* action is now sent exactly once on an ambiguous failure and surfaces AmbiguousOutcomeError naming the read to verify with before resubmitting; retries only on failures that provably happened before Tebra could act26 d
stablecoin.xyz facilitator
stablecoinxyz/x402-facilitator · live x402 settlement
FIXEDA receipt read that failed after transferFrom() was broadcast returned success:false with no hash and no ledger row, and the re-presented payment was answered permit_signature_invalid, inviting a second payment on a fresh nonce#6 → PR #7: a broadcast transfer is never answered terminally, Solana settlements validated3.8 d
inflow x402-seller
inflowpayai/inflow-node · seller SDK for the Inflow facilitator
FIXEDensurePaymentIdentifier minted a fresh random id per call, so the core's identical-payload pending retry reached the facilitator as a second payment; the facilitator's 409 idempotency-pending answer was also not the response the retry helper expected#54 (failing test in their own harness) → @inflowpayai/x402-seller@0.7.1: stable identifier across settlement attempts, pending answers retried with the same request2.6 d
KeeperHub
KeeperHub/keeperhub · hosted workflow marketplace, USDC per call
FIXEDMCP call_workflow and the marketplace call route carried no Idempotency-Key, so a retried paid call could charge twice#2208 (reported by a community contributor; confirmed and closed by the team) → PR #2215: key honoured on both surfaces. Whether the default client re-signs on a timeout is still the open question on the thread7.9 d
mergewatch
mergewatch/mergewatch.ai · code-review SaaS, Stripe-billed
FIXEDRe-reviewing an unchanged commit reused the Stripe idempotency key with a different amount, so the usage ledger and Stripe disagreed and the divergence was only a log warning; the maintainer reframed it as a ledger-divergence defect, which is the honest reading#563 → PR #5733.6 d
21 implementations
facilitators, wallets, payment SDKs, MCP servers
UNDER DISCLOSURESame seam, reported privately or as a finding-first issue with the fixNamed here only after they ship. Counts updated as they close.open
Everything elseUNREAD—No verdict is implied by absence. Unread means unread.—

Also fixed outside payments after our reports: mcp-server-kibana #12, #13, atlassian-confluence-mcp-server #55, currents-mcp #163 (reported 9 Aug; request.ts now tells "never sent" from "sent, answer lost" and retries only the first; in the public repo from 17 Sep, closed 2 Oct).

Method

Three evidence tiers, always labelled. A verdict never rests on a claim we cannot link.

Battery run — the strong tier

The client makes one purchase against hostile-facilitator, which settles and then misbehaves on cue, counting how many distinct payments actually arrived. One is safe. Two is the double-charge.

Why a spec-conformance suite cannot reach this. A read-only conformance checker probes with a signature that can never authorize, on purpose, so that it is safe against a live deployment. That is the correct design, and it draws a hard line: a suite that never settles once cannot observe a second settlement. Those tools grade what a facilitator says against the specification. This grades what its money does. Both are worth running; only one of them can catch a double charge, and a facilitator can pass every Required clause while taking a payment twice.

  • accept_then_timeout — settles, hangs past your timeout
  • 5xx_after_settle — settles, returns 502
  • double_402 — re-challenges a request that already paid
  • slow_answer — settles, answers just under the wire
  • reconcile_unavailable — settles ambiguously, and the "did it land?" read also fails
  • declared_safe — checks you are not over-refusing
  • clean — control

The reconcile read. Four of the ten modes (reconcile_unavailable, reconcile_soft_404, reconcile_oversized, reconcile_truncated) attack the "did it land?" read itself. None of the eight SDKs scored in October has such a read, so those modes are reported as not reached and the verdict is INCOMPLETE, never PASS. For exact on EVM the payer can answer the question from the token contract, with no facilitator in the path: USDC authorizationState(payer, nonce) consumed means settled and AuthorizationUsed names the transaction; unused past validBefore means it can never settle, release it; unused and still valid means hold and re-present the same bytes, never a new nonce. Credit: domondi1 (Inferrail) on x402#3438, reference code in inferrail/examples/agent_economy (simulated USDC, not mainnet). Scheme-specific: upto and rails without a nonce-consumption read still have no payer-side answer.

Self-run, control published — the implementer runs the battery themselves and publishes the result, the mutation control, and the command. Reproducible by any reader; not independent. Labelled exactly that way in the ledger, between a code read and an independent run.

Code read — the honest tier

A line-by-line read of the settle, retry and signing paths, written up as a public issue with the mechanism, why the existing guards do not cover it, the minimal fix, and the test that would have caught it. Every finding is checked against the implementer's own defences before it is filed, and each report states its own ceiling: a code read is not a live reproduction.

  • Verdicts by code read are marked as such in the ledger.
  • A finding becomes public only after the gate that refuses to name a company next to an unfixed claim.
  • Nothing here is a CVE, an exploit, or an accusation — it is a reliability seam with a fix attached.

Who pays when it fires twice

Every finding carries one of three verdicts, because this is the question asked immediately after "was one found." We do not pay the claim — we tell you which of the three you are in, with a battery run and a line number.

VerdictWhat it meansWhat follows
Licensed-path defectThe money path itself turned an unknown outcome into a second payment — the settle that timed out after it landed, the retry that signed a fresh authorization, the guard that released on an error that wasn't one.The operator of that path owes their customer. Fix and test attached; the row goes up with credit on the day they ship.
Credential outside the pathThe extra charge came from something holding the provider secret directly, bypassing every guard that was built. The guards held; the key did not stay where the guards are.Not a defect in the path, and the report says so plainly — named as the shape of leak it is.
Undetermined — heldWhether a second record is possible could not be established from the code or a reproduction.Reported as undetermined. Never as safe, never as found. Nobody gets to guess; the intent stays open.

The third row is what makes the other two worth anything — it is the same rule the code is graded against, applied to our own report. What a review returns, specified in full →

Get on this page — free

Submitting is free and always will be. Any client, facilitator or SDK that signs, sends, settles or retries an agent payment — yours or someone else's — gets read and graded here at no cost. If a finding is confirmed you are counted, never named, until you ship a fix; when you do, the row goes up with credit and your time-to-fix as the headline. Findings come back with the mechanism, the file and line, and a failing test, no strings attached.

Submit for grading — free

Or check yourself first, offline: npx -y effectfence demo shows the double-charge on your own machine in ten seconds; hostile-facilitator test -- <your purchase command> runs the whole battery. MIT, and it ships with a mutation control so you can confirm the instrument can fail before you trust it passing you.

The one thing that costs money

A full battery run against your live system — the one thing we cannot do without your cooperation. Every ambiguous outcome driven against your real client or facilitator, settlements counted at the facilitator rather than inferred from responses, and a mutation control proving the instrument can fail. A clean run earns a VERIFIED SAFE · by battery run row and a badge you can display. Nothing above this line requires it.

See exactly what you get before you pay. This is a complete deliverable — a real 10-mode run against a deliberately broken client, seven modes double-paying, signed and timestamped in Sigstore's public log (logIndex 2796196402). The subject script is committed next to it, so you can reproduce the run yourself. Yours is the same artefact with your client as the subject. It is published failing on purpose: an instrument that has never gone red is decoration.

1 · Pay — $1,200 2 · Send your repo

Two steps, no call. Findings come back on your request within a week; a clean battery run earns the badge within 24 hours. What's included.

Self-test first, free: npx -y effectfence demo shows the double-charge on your own machine in ten seconds; hostile-facilitator test -- <your purchase command> runs the whole battery.

Founding conformance run — we run it, $300 · first three implementations

Between the two rungs above: we run the full battery against your implementation and the result is published on this page, named. That publication is the condition, not an extra — a founding rate buys a public result, and a verification nobody can check is not one. Findings come back within five business days; a clean run earns a VERIFIED SAFE · by battery run row within 24 hours.

If you need the result kept private, that is the $1,200 attestation run above, not this rung.

Founding conformance run — $300

Three only, then the standard rate is $1,200.

Founding badge — self-run, signed, $99 · first 10 servers

The same battery, run by you on your own server, and the result signed and anchored by us so a reader can verify it without trusting either of us. No reply needed, no scheduling, nothing to send us but a file. Labelled self-run, control published on this page — the third evidence tier, exactly as it is.

  1. Pay: $99, one-off. The receipt email is where step 4 goes.
  2. Run the battery against your server: pip install "git+https://github.com/aurumflux20/hostile-facilitator@v0.2.0" then hostile-facilitator test --json result.json -- <your one-purchase command>. Run the mutation control too (hostile-facilitator selftest) so the record shows the instrument can fail.
  3. Record it: pip install "coherence-check[attest]" then coherence conformance result.json --out session.json. A mode where your client paid twice is recorded open, never proven — a failing run cannot be signed green by anyone, including us.
  4. Reply to the receipt with result.json and session.json. Within 24 hours you get attestation.json plus a Sigstore Rekor anchor, and this one-liner any reader can run: coherence verify attestation.json --pub <our key> --session session.json --rekor attestation.rekor.json.
Founding badge — $99

Ten only, then this rung closes. A clean run earns a VERIFIED SAFE · self-run, signed row and a badge; a failing run earns a private note with the failing mode and nothing on this page. A real signed example, verifiable now.