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

# Errors

> Parse Spritz problem responses consistently.

The Spritz API returns errors as [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457)
problem details: a standard, machine-readable JSON shape served as
`application/problem+json`. Build your error handling against it once and it works
across every endpoint. Accept `application/json` as a compatibility fallback.

## Problem shape

```json theme={null}
{
  "type": "urn:problem-type:validation:invalid-request",
  "title": "Invalid Request",
  "status": 400,
  "detail": "Deposit exceeds the current maximum deposit amount.",
  "instance": "/v1/deposits/direct/prepare",
  "code": "transaction_limit",
  "field": "amountUsd"
}
```

| Field      | Description                                                                                                 |
| ---------- | ----------------------------------------------------------------------------------------------------------- |
| `type`     | A `urn:problem-type:` URI identifying the broad error category.                                             |
| `title`    | Short, human-readable summary of the error category.                                                        |
| `status`   | HTTP status code, repeated in the body.                                                                     |
| `detail`   | Human-readable explanation specific to this occurrence.                                                     |
| `instance` | URI of the specific request that failed.                                                                    |
| `code`     | A stable, endpoint-specific discriminator when present. ACH debit integrations should branch on this field. |
| `field`    | The request field associated with the problem, when present.                                                |

Some problems include **extension members** alongside the standard fields for
additional context, for example `code`, `realm`, `scope`, `resourceType`, and
`resourceId`. Treat unknown extension members as optional.

## Status codes

| Status | Meaning                                                                       |
| ------ | ----------------------------------------------------------------------------- |
| `400`  | Malformed request, such as invalid parameters or body.                        |
| `401`  | Missing or invalid credentials. See [Authentication](/guides/authentication). |
| `403`  | Authenticated, but not permitted for this resource.                           |
| `404`  | Resource not found.                                                           |
| `409`  | Conflict, such as a duplicate or a state that can't transition.               |
| `422`  | Validation failed on an otherwise well-formed request.                        |
| `429`  | Rate limited. See [Rate Limits](/guides/rate-limits).                         |
| `5xx`  | Something went wrong on Spritz's side. Safe to retry idempotent requests.     |

## Handling errors

Branch first on the HTTP status and `type`. When `code` is present, use it for the
specific product outcome. Several ACH debit errors intentionally share the same broad
problem `type`, so `type` alone cannot distinguish a limit, an ineligible bank, and a
program pause. Never branch on `title`, `detail`, or provider failure text; those are
human-readable and may change.

`code` is optional. For a code-less `409`, treat the state as an unresolved concurrent
conflict: wait, read the affected resource, and replay only an idempotent request with
the same key and body. For any other unknown or code-less problem, show a safe generic
message, and do not invent product behavior.

Every response includes `X-Request-ID` and `X-Correlation-ID` headers. Persist both
with failed operations and include them when your support team escalates to Spritz.
They are transport metadata, not fields inside the Problem Details body.

```ts theme={null}
const res = await fetch(url, { headers });

if (!res.ok) {
  const problem = await res.json();
  switch (problem.code) {
    case "transaction_limit":
      await refreshDepositLimits()
      break;
    default:
      logForSupport(problem)
  }
}
```

The linked-bank guide lists the complete ACH debit
[`code` handling matrix](/guides/use-cases/linked-bank-onramp#when-a-deposit-is-blocked).
