
# Errors

Baton returns conventional HTTP status codes and a JSON error body. This page covers the errors you are most likely to meet and what to do about them.

## Payment errors (402)

A payment that fails admission returns `402` with an x402 error body:

```json
{"x402Version": 2, "error": "PAYMENT_REQUIRED", "errorReason": "<reason>"}
```

| `errorReason` | Meaning | Fix |
|---|---|---|
| `replay` | The payment nonce was already used. | Sign a fresh authorization with a new nonce. |
| `authorization_expired` | `validBefore` is in the past. | Re-sign with a later `validBefore`. |
| `authorization_not_yet_valid` | `validAfter` is in the future. | Set `validAfter` to `0` or a past time. |
| `invalid_max_amount` | The authorized amount does not match the price. | Quote the baton first; authorize the quoted amount. |
| `invalid_token` | The asset is not a supported stablecoin contract (USDC or EURC) for the active network. | Use the USDC or EURC contract address for the active network. |
| `merchant_not_configured` / `settler_not_configured` | A server-side payment configuration gap. | Transient — retry; if it persists, contact support. |

For developers on a prepaid balance, an insufficient balance is also a `402` — top up and retry.

## Baton state errors (409)

A `409 Conflict` means the baton's state does not allow the operation:

- **`BATON_WITNESSED`** — the baton has been document-witnessed and is locked for writes. A witnessed baton is read-only by design.
- **`CHAIN_FLAG_CONFLICTS_OVERWRITE`** — you sent an overwrite-style write to a hash-chained baton. A chain only grows; append instead.

## Not found (404)

A `404` means the baton id or token does not exist, has been hard-deleted, or — for a token — has expired or been revoked. A baton inside its tombstone window is recoverable; one past it is gone.

## Idempotency

Every billable call requires an `Idempotency-Key` header. If a call fails midway — a dropped connection, a timeout — retry it with the **same** key. Baton recognises the key, returns the original result, and does not charge you twice. A retry with a *new* key is a new, separately-billed call.

## Limits and warnings

When a baton is running low on a resource — egress, time, writes — Baton does not wait for it to fail. Successful responses carry inline warnings while there is still allowance left, so you can extend the baton before it expires. Treat a warning as a prompt to act, not an error.
