Blog, by , , 8 min read

x402 settlement failed or pending? What to do

An x402 payment verifies but doesn't settle: what settlement_pending means, how to reconcile the transfer, and how not to charge a buyer twice.

8min read
On this page
  1. First: which step failed?
  2. Verification failed: fix the payload
  3. Settlement failed with an empty transaction: nothing moved
  4. Settlement pending: the case that charges people twice
  5. Why the same authorization can't double-charge
  6. Is the x402 facilitator down?
  7. Checklist
  8. Frequently asked questions

Short answer: an x402 payment goes through two facilitator calls, /verify and /settle, and most "payment failed" reports are one of three different things: verification rejected the payment (nothing was broadcast, fix the payload and sign again), settlement failed for a terminal reason (nothing moved, the transaction field is empty), or settlement is pending (the transfer was broadcast and may still confirm). The third case is the dangerous one: a seller who treats it as a failure and asks for a new payment, or a buyer who signs a fresh authorization, can pay twice, because the retry carries a new nonce. Retrying the same signed authorization is safe, since the exact scheme's nonce is single-use.

This post is the decision tree, as of 18 October 2026.

Some background: x402 lets a client, usually an AI agent, pay for an HTTP request in stablecoins. The server never touches the chain itself. It hands the buyer's signed payment to a facilitator, which the x402 v2 specification describes as "HTTP REST APIs for payment verification and settlement": POST /verify "verifies a payment authorization without executing the transaction on the blockchain", and POST /settle "executes a verified payment by broadcasting the transaction to the blockchain". Verification answers with isValid and, on failure, invalidReason. Settlement answers with success, errorReason when it failed, the transaction hash ("empty string if settlement failed"), the network and the payer.

First: which step failed?

Decode the response before you do anything else. Over HTTP the receipt is the PAYMENT-RESPONSE header, base64 JSON, and the transport spec returns 402 for both a failed verification and a failed settlement (and 400 for a malformed payload), so the status code alone doesn't tell you which. Over MCP it is the _meta["x402/payment-response"] field or a tool result marked isError, as described in how x402 over MCP works. Then read two fields:

success transaction What happened
true hash Settled. Deliver once, log the hash.
false empty Nothing was broadcast. Read errorReason; it is terminal unless the facilitator's docs say otherwise.
false hash Broadcast, outcome unknown. Treat as pending, not failed.

The spec's section 9 lists the error reasons a facilitator or resource server may return, among them insufficient_funds, invalid_exact_evm_payload_signature, invalid_exact_evm_payload_authorization_valid_before, invalid_exact_evm_payload_authorization_value_mismatch, invalid_exact_evm_payload_recipient_mismatch, invalid_network, invalid_payload, invalid_scheme, unsupported_scheme, invalid_transaction_state, unexpected_verify_error and unexpected_settle_error. Coinbase's troubleshooting page adds settlement-only codes for its facilitator such as settle_exact_failed_onchain and settle_exact_node_failure, and says of the three codes where "the payment may or may not have landed" (two Solana confirmation timeouts and invalid_exact_evm_verification_failed): "Resolve them by confirming the transaction rather than by retrying."

Verification failed: fix the payload

If the 402 comes back with a verification reason, no money moved and the problem is in the request. Coinbase's troubleshooting page lists the usual causes: the payer's balance is short or on the wrong network; client and route share no scheme and network; the amount is off ("the exact scheme requires equality on EVM, so neither underpayment nor overpayment settles"); the authorization has expired (validBefore in the past); or compliance screening declined the payer, which returns kyt_risk_detected and "is not retryable". A persistent invalid_payload is often a version mismatch: a v1 client sends X-PAYMENT, a v2 server expects PAYMENT-SIGNATURE, and the page recommends upgrading the @x402 packages together.

The same invalid_payload is what Coinbase's facilitator returns when you re-present an authorization whose nonce was already spent. So if you see it on a retry, check whether the first attempt actually landed before you conclude the payload is broken.

Settlement failed with an empty transaction: nothing moved

A terminal settlement failure with no hash means the facilitator never got the transfer on-chain: a reverted simulation, a node error, a failed on-chain call. Coinbase's FAQ says a settle call that fails "with a 4xx or 5xx, including a payment declined by compliance screening" is not billed, and verification is always free. For the seller, don't deliver, log the reason through the onSettleFailure hook if your SDK has one, and let the client decide whether to pay again. This is the one case where a fresh authorization is the right next step.

Settlement pending: the case that charges people twice

Coinbase documents a third outcome on its settlement pending page: /settle returns success: false, errorReason: "settlement_pending", a non-empty transaction and the network, with HTTP status 500, so a "5xx means failed" branch is precisely the mistake. The facilitator broadcast the transaction but didn't see it confirm within the synchronous settlement window. The page calls it "a non-terminal outcome" and states the rule plainly: "A missing or pending receipt is not a failed payment."

What goes wrong without that rule is easy to trace. The buyer's SDK sees a 402, so it does what it does on every 402: builds a new PaymentPayload with a fresh nonce and signs again. If the first transfer confirms a few seconds later, both land. The same hazard is described in two open bug reports against open-source facilitators, not yet confirmed by their maintainers, where a receipt timeout after broadcast is reported as a plain failure with no hash, so the client can't tell "already settled" from "never settled" (one, another). Whatever any one implementation does, a 402 after broadcast invites a second signature.

Coinbase's guidance for sellers, which applies whichever facilitator you use:

  1. Don't create a new payment, change the requirements or broadcast a replacement until the original is reconciled.
  2. Keep the original request in full: x402Version, paymentPayload, paymentRequirements, plus the returned network and transaction.
  3. Look up the transaction on that network with an RPC provider or a block explorer; on EVM chains that's eth_getTransactionReceipt for the hash.
  4. Resend the original settle request unchanged, once, if you want the facilitator to check again. The canonical resource-server SDKs in TypeScript, Python and Go already do this: on settlement_pending with a non-empty transaction they re-send the same payload once, and the facilitator checks the existing transaction instead of broadcasting a new one. A direct call to the facilitator API gets no such retry.
  5. Deliver once, on success. When the transaction confirms or settle returns success: true, record it as settled and deliver. On a revert, failure or expiry, treat it as failed, and only then ask for a new payment.

Why the same authorization can't double-charge

With the exact scheme on EVM chains the buyer signs an EIP-3009 transferWithAuthorization with a nonce, and the scheme spec says the facilitator "cannot modify the amount or destination" and serves "only as the transaction broadcaster". Coinbase's troubleshooting page draws the conclusion: "retrying the same authorization cannot charge the buyer a second time" because "the exact scheme's authorization nonce is single-use". A replay is rejected, not re-settled.

That gives you a simple test when a buyer reports a double charge: compare the two payloads. Identical payloads mean a failed or pending settlement followed by a successful retry, which is one charge. Different payloads mean the buyer's client signed twice, and the fix is on the client: don't sign a new authorization while the previous one is pending. For idempotency across different payments the x402 payment-identifier extension gives the client a key to send; Coinbase's FAQ notes the CDP SDK doesn't enable it by default.

Is the x402 facilitator down?

Sometimes nothing is wrong with your code: the facilitator is unreachable or its RPC is rate-limited, and every paid request fails until it recovers. ToolVet checks the public /supported endpoint of each facilitator it knows every 5 minutes and shows the result on the facilitator status pages. As of 18 October 2026 the three facilitators ToolVet checks (PayAI, Dexter and the x402.org testnet facilitator) were up, with 30-day uptimes between 99.7% and 100%; Coinbase's facilitator isn't checked because its /supported endpoint needs an API key. A /supported check proves the facilitator answers, not that settlement is fast; for that, compare your timings with what the facilitator publishes. Coinbase's P95 targets are settlement in 900 ms on Base and 1,500 ms on Solana (FAQ). If your settle calls take far longer, the facilitator is where to look, and switching is a configuration change.

Checklist

For sellers: branch on success and transaction, never on the HTTP status alone; store the full settle request and the returned hash before you answer the buyer; on a hash without confirmation, re-send the identical settle request once and then poll the chain, and don't re-challenge; deliver once, after a terminal success, and make tools with side effects idempotent.

For buyers and agents: log the decoded PAYMENT-RESPONSE (or x402/payment-response) with every paid call, since the transaction hash is your receipt; on a 402 after you paid, read the reason before paying again, because a hash means wait and verify, not re-sign; keep maxAmountPerPayment close to the prices you expect, so a retry bug is bounded; and check the challenge before the first payment with the free x402 checker or the preflight_check tool on the ToolVet MCP server, which never pay.

Frequently asked questions

Why does my x402 request still return 402 after I paid?

Because the server rejected the payment rather than ignoring it, and the reason is in the response: over HTTP in the decoded PAYMENT-RESPONSE header, over MCP in the error result. Verification reasons (wrong network, expired validBefore, wrong amount, screening) mean nothing was broadcast; settlement_pending with a transaction hash means the transfer is in flight and you should wait for it rather than sign again.

What does settlement_pending mean in x402?

The facilitator broadcast the transfer but did not see it confirm within its synchronous settlement window. Coinbase documents it as a non-terminal outcome: the seller keeps the original request, looks up the transaction on the named network, re-sends the identical settle request at most once, and delivers once it confirms. Asking the buyer for a new payment while it is pending can charge them twice.

Can an x402 payment be charged twice?

Replaying the same signed authorization cannot, because the exact scheme's nonce is single-use and the facilitator rejects the replay. Signing a new authorization while the first transfer is still pending can, since each nonce is a separate transfer. Compare the two payloads: identical means one charge, different means two signatures.

How do I know whether the facilitator itself is down?

ToolVet probes each facilitator's /supported endpoint every 5 minutes and publishes the result, a 30-day uptime and an Atom feed on its facilitator status pages. That tells you whether it answers; for settlement latency compare your own timings with the facilitator's published targets.

The counts and uptimes above are as of 18 October 2026. How we check and score explains how ToolVet checks endpoints and facilitators without paying them.