Why
The facilitator removes blockchain plumbing from the seller; it does not remove distributed-systems semantics. A paid API needs an idempotency key and a durable payment-to-resource state machine.
x402 makes stablecoin payment look like ordinary HTTP middleware: the server returns payment requirements, the client signs, and a facilitator verifies and settles. The difficult boundary appears when one stage succeeds and the next response is lost.
How it works
Put one idempotent API behind @x402/express, inject failures between verify, settle, and fulfillment, then prove that one signed payment produces at most one charge and one response entitlement.
PoC
Protect one idempotent API route with @x402/express. Inject a timeout after verification, after on-chain submission, after settlement, and after resource generation. Retry the identical signed request and assert two invariants: at most one payment settles, and one settled payment always maps to one durable entitlement.
What it proves
A facilitator removes node operation and settlement submission from the seller, but it cannot make a distributed workflow atomic. The application still needs a payment identifier, durable state, replay handling, and reconciliation between facilitator results and canonical receipts.
References: x402 facilitator, x402 v2 SDK.
Review clarification
The demo ends where the product begins
Returning HTTP 402 with payment requirements is an hour of work; the middleware makes the demo almost free. What the middleware cannot give you is the thing that makes it a product: the moment money moves in one system (the chain) and the good is delivered in another (your API), you have a distributed transaction, and distributed transactions cannot be made atomic. The real work sits exactly where the demo ends — the retry.
The failure window is between the stages
One "paid request" is four stages — verify → submit → settle → fulfill — each crossing a network boundary that can eat the response. That is why the PoC injects a timeout after each stage rather than failing the stages: every stage succeeded, only the response was lost, and the client does the only rational thing and retries the identical signed request.
| Window | What is true | What the retry must do |
|---|---|---|
| After verify | Nothing settled, no money moved | Re-verify and continue — the cheapest window |
| After submit | The dangerous one: did the transfer land? | The authorization nonce makes the chain refuse a second settle — so read "already used" as this payment already succeeded, never as an error to show the user |
| After settle | Money moved, no product yet | The debt exists only in your database — it must have been recorded durably before the crash |
| After fulfill | Resource exists, delivery lost | Return the same resource, never generate again |
Misclassifying the second window is how a paying customer gets an error screen for a payment that worked.
The two invariants are the whole product
At most one settled payment per signed request; exactly one durable entitlement per settled payment. Everything else — middleware, facilitator, SDK — is replaceable plumbing. This is exactly the Web2 payments playbook: Stripe's Idempotency-Key and a durable state machine (received → verified → submitted → settled → fulfilled) keyed by the payment nonce. x402 changes the rail, not the semantics. "Settlement owns the retry" means retry handling cannot live in generic HTTP retry logic; a retry is a lookup about an existing payment first, and a new attempt only after that lookup says so.
Vigilance is not the deliverable
You cannot monitor your way out of a double charge — by the time you see it, the money moved twice. The guarantee has to be structural: assume every response can be lost, treat the retry as the normal path, and ask in design review, for each arrow in the flow, "what happens if the response after this arrow is lost and the same request arrives again?" If any arrow answers "we charge again" or "we deliver nothing," that arrow is the bug — before any code is written. The reconciliation line at the end is receipt-is-not-settlement again: the facilitator saying "settled" is one service's claim; the canonical receipt on chain is the authority. And the reason x402 matters at all is agent commerce — pay-per-request with no account and no API key is the rail an AI agent would use.