# Payment errors

Find which stage a failed payment died at, and whether retrying can fix it.

Section: Understand x402
Source: https://www.roundhouse.studio/docs/x402/errors

---

Almost every broken x402 integration is one of the failures below. Start by finding **which stage**
failed: about half never fix themselves on retry, so retrying blind burns gas and rate limit for
nothing.

## Read the stage first

A well-behaved endpoint names the stage it failed at. Roundhouse's own endpoints use these:

| Stage | Meaning | Retry? |
| --- | --- | --- |
| `input` | Your request body was malformed | No — fix the request |
| `signature` | The signature did not recover to the claimed address | No — fix the signing |
| `fee` | The service fee leg failed | Maybe |
| `verify` | The facilitator rejected the authorization | **No** |
| `settle` | Verified, but the broadcast failed | Yes |
| `facilitator` | The facilitator itself was unreachable or errored | Yes |

The line to internalise: **`verify` failures never fix themselves.** A bad signature, a reused
nonce, an expired window or an insufficient balance are all deterministic. If you retry a `verify`
failure unchanged, you will get the same answer forever.

## The five that account for most of it

### 1. Signing the wrong thing

*Symptom:* `verify` fails with something like "signature does not authorize this transfer".

You used `personal_sign` over the JSON requirement instead of signing typed data over the token's
EIP-712 domain. No facilitator can verify the former — it is a signature over a different message
entirely. Every historical "402, no settlement" mystery has eventually been this.

Fix: `signTypedData` with `primaryType: 'TransferWithAuthorization'`, domain taken from the token
contract. See [anatomy of a payment](https://www.roundhouse.studio/docs/x402/anatomy-of-a-payment).

### 2. Address casing

*Symptom:* identical message, "signature does not authorize this transfer".

Typed-data libraries validate EIP-55 checksums *inside* the hash function, so a lowercase or
mis-cased address produces a different hash — and the failure surfaces as a signature problem at the
facilitator, which cannot be debugged from that end at all.

Fix: canonicalise every address to its checksummed form before anything hashes it.

### 3. Amount interpreted as decimal

*Symptom:* "Payer balance N is less than the authorized M", with an absurd M.

`maxAmountRequired` is atomic units in a string. USDC has 6 decimals, so `"10000"` is $0.01. A
client that reads it as `10000` USDC will ask to move ten thousand dollars.

Fix: never convert. Pass the string through as `value`.

### 4. Chain not served

*Symptom:* `500`, or a `verify` failure saying something like "Chain 84532 not supported by this
facilitator". Reads like a payment problem; is a configuration problem.

`x402.org/facilitator` is **testnet only**. The Roundhouse facilitator serves **Base mainnet**.
Neither serves the other.

Fix: `GET /supported` on your facilitator before you build against it. See
[schemes and networks](https://www.roundhouse.studio/docs/x402/schemes-and-networks).

### 5. Nonce reuse or a stale window

*Symptom:* `verify` fails, and the same payload previously worked.

The `nonce` is single-use, enforced by the token contract. And an authorization whose `validBefore`
is within a few seconds is rejected rather than raced.

Fix: 32 fresh random bytes per attempt, and a `validBefore` comfortably beyond the resource's
`maxTimeoutSeconds` — ten minutes is a sane default.

## The base64 trap

Worth its own heading because the error message points nowhere useful.

```text
500 No facilitator registered for x402 version: undefined
```

Base64 is the *`X-PAYMENT` header's* encoding. When you call `/verify` or `/settle` directly,
`paymentPayload` must be the **decoded object** — a facilitator reads `x402Version`, `scheme` and
`network` off it. Hand it a string and every one of those is `undefined`.

## Roundhouse endpoint error codes

For [`/v0/test/x402`](https://www.roundhouse.studio/docs/guides/first-x402-payment) and the SQL endpoint:

```text
402 payment_malformed   no EIP-3009 authorization + signature in the header
402 payment_invalid     the facilitator rejected the payment (detail says why)
402 payment_failed      verified, but settlement failed on-chain
409 key_already_issued  that settlement already bought a key — pay again
500 key_issue_failed    settled but key issuance broke; the tx hash is in the body

400 invalid_query       failed the SQL sandbox checks
401 invalid_api_key     key not found, revoked, or expired
402 insufficient_qu     organization is out of Query Units
429 rate_limited        too many requests this minute
400 query_failed        the query ran but errored (timeout, bad column, …)
```

`409 key_already_issued` is the one people misread: your payment succeeded, and a key was already
minted against that settlement. It is not a duplicate charge — it is a refusal to mint twice for one
payment.

## A prompt for debugging one

```prompt
An x402 payment is failing. Diagnose it without retrying blindly.

1. Show me the raw 402 response body, decoded.
2. Show me the X-PAYMENT envelope you built, base64-decoded, and confirm:
   - value is atomic units as a string
   - to equals the requirement's payTo, EIP-55 checksummed
   - validBefore is at least 300 seconds in the future
   - nonce is 32 fresh random bytes
3. Fetch GET /supported on the facilitator and confirm the scheme and network
   you are using appear in it.
4. Name the failure stage. If it is `verify`, do NOT retry — tell me which of
   the four deterministic causes it is.
```

## Next steps

- [Anatomy of a payment](https://www.roundhouse.studio/docs/x402/anatomy-of-a-payment) — the fields, in order
- [Facilitators](https://www.roundhouse.studio/docs/x402/facilitators) — what verify actually checks
- [Platform status](https://www.roundhouse.studio/status) — if the failure might be ours

---

Every page in these docs is available as markdown at its own URL plus `.md`.
Full index: https://www.roundhouse.studio/docs.md
