# 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.

Published 2026-10-18. Source: https://toolvet.app/blog/x402-settlement-failed-or-pending

**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](https://www.x402.org) 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](https://github.com/coinbase/x402/blob/main/specs/x402-specification-v2.md) 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](https://github.com/coinbase/x402/blob/main/specs/transports-v2/http.md) 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](https://toolvet.app/blog/paid-mcp-tools-x402-over-mcp). 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](https://docs.cdp.coinbase.com/x402/support/troubleshooting) 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](https://docs.cdp.coinbase.com/x402/support/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](https://docs.cdp.coinbase.com/x402/seller/settlement-pending): `/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](https://github.com/mogami-tech/x402-facilitator/issues/167), [another](https://github.com/qntx/facilitator/issues/73)). 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](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) 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](https://toolvet.app/status/facilitators). 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](https://docs.cdp.coinbase.com/x402/support/faq)). If your settle calls take far longer, the facilitator is where to look, and [switching](https://toolvet.app/blog/x402-facilitators-compared) 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](https://toolvet.app/blog/x402-payment-challenge-checks) before the first payment with the free [x402 checker](https://toolvet.app/check) or the `preflight_check` tool on the [ToolVet MCP server](https://toolvet.app/agents), 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](https://toolvet.app/status/facilitators). 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](https://toolvet.app/methodology) explains how ToolVet checks endpoints and facilitators without paying them.
