> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xentfi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Error Handling

> Error classes, retry behavior, and HTTP status mapping for the x402 Facilitator SDK.

`verify()` and `settle()` **throw** on failure rather than returning a falsy result — there is no `{ isValid: false }` shape to check. Wrap calls in `try`/`catch` and use the error classes below to decide how to respond.

## Error classes

| Class                         | When it's thrown                                                                                                          |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `X402FacilitatorConfigError`  | Missing required config (`apiKey` or `orgId`) — thrown synchronously by the constructor, before any network call.         |
| `X402FacilitatorNetworkError` | The network request itself never completed (DNS failure, timeout, connection refused). Automatically retried — see below. |
| `X402FacilitatorError`        | The facilitator returned an unexpected HTTP status. Carries a `.statusCode` property.                                     |

```ts theme={null}
import {
  X402FacilitatorClient,
  X402FacilitatorError,
  X402FacilitatorConfigError,
  X402FacilitatorNetworkError,
} from "@xentfi/x402-facilitator-sdk";

try {
  const facilitator = new X402FacilitatorClient({ apiKey, orgId });
  await facilitator.verify(payload, requirement);
} catch (err) {
  if (err instanceof X402FacilitatorConfigError) {
    // apiKey/orgId missing — a setup bug, fix before deploying
  } else if (err instanceof X402FacilitatorNetworkError) {
    // exhausted retries against a genuine network failure
  } else if (err instanceof X402FacilitatorError) {
    console.log(err.statusCode, err.message);
  }
}
```

## HTTP status mapping

The facilitator's error handler returns consistent error responses with these status codes:

| Code  | Meaning                                                                                               |
| ----- | ----------------------------------------------------------------------------------------------------- |
| `402` | Payment or verification failed (invalid signature, expired authorization, amount/recipient mismatch). |
| `400` | Bad request or validation error.                                                                      |
| `401` | Authentication error — invalid or missing `apiKey`/`orgId`.                                           |
| `403` | Authorization error — credentials valid but insufficient permission.                                  |
| `404` | Resource not found.                                                                                   |
| `500` | Internal server error.                                                                                |

<Note>
  A `402` response from `/verify` or `/settle` is a normal, expected outcome for an invalid or expired payment — not a bug in your integration. Surface `err.message` back to the payer in your own `402` challenge response's `error` field (see [Resource Server Guide](/x402/resource-server)) so their agent can retry correctly.
</Note>

## Automatic retries

Requests are retried automatically on `X402FacilitatorNetworkError` (i.e. the request never got a response at all) with exponential backoff and jitter:

| Attempt   | Base delay | With jitter (up to +25%) |
| --------- | ---------- | ------------------------ |
| 1         | —          | immediate                |
| 2         | 250ms      | \~250–312ms              |
| 3 (final) | 500ms      | \~500–625ms              |

Requests that *do* get a response — including `402`s and other HTTP error statuses — are **not** retried automatically, since a `402` or `4xx` is a deterministic outcome that won't change on retry without a different payload.

## Common scenarios

<AccordionGroup>
  <Accordion title="X402FacilitatorConfigError: apiKey is required">
    Thrown immediately by the constructor if `apiKey` (or `orgId`) is missing. Check your environment variables (`WAAS_API_KEY`, `WAAS_ORG_ID`) are set before constructing `X402FacilitatorClient`.
  </Accordion>

  <Accordion title="402 from verify() — invalid signature">
    The signed EIP-712 message doesn't match what the contract/facilitator expects — usually a wrong `Eip3009TokenDomain` (see [Signing Reference](/x402/signing)) or a payload that was tampered with in transit.
  </Accordion>

  <Accordion title="402 from verify() — expired authorization">
    `validBefore` has passed. Either the payer waited too long between signing and sending, or `validitySeconds` was set too short for the round trip. Have the payer re-sign a fresh authorization.
  </Accordion>

  <Accordion title="402 from settle() — nonce already used">
    The same `(from, nonce)` pair was already submitted on-chain. If you intentionally reuse deterministic nonces for idempotency, this is expected on a genuine retry of an already-settled payment — check `xentfi_get_payment`-style transaction history (or your own settlement log) before treating it as an error.
  </Accordion>

  <Accordion title="401 Unauthorized">
    Invalid or revoked `apiKey`/`orgId`. Verify both against the [dashboard](https://dashboard.xentfi.com).
  </Accordion>
</AccordionGroup>

See [API Reference: Error Handling](/api-reference/errors) for the platform-wide error code and status conventions this builds on.
