# Errors and status codes

> The error body shape, every status code the API returns and what to do about each, plus the no-match reasons on search.

Source: https://sightradar.com/docs/errors

## Error body

Every non-2xx response is JSON:

```json
{
  "error": "insufficient credits",
  "error_code": "insufficient_credits",
  "error_detail": {
    "code": "insufficient_credits",
    "message": "Wallet balance too low for this operation.",
    "docs_url": "https://sightradar.com/docs/billing"
  }
}
```

`error` is human-readable and may change. `error_code`, when present, is stable and the field to branch on.

## Status codes

| Status | Meaning                                                                                                           | What to do                                                                                      |
| ------ | ----------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `400`  | Bad request: missing field, undecodable image, no `url`/`gcsKey`/body, base64 in batch.                           | Fix the request. Not charged.                                                                   |
| `401`  | Missing or invalid API key.                                                                                       | Check the `Authorization` header and that the key is not revoked.                               |
| `402`  | Wallet balance too low.                                                                                           | Top up, or enable [auto-recharge](/docs/billing#auto-recharge). Control-plane calls still work. |
| `403`  | Account is read-only (for example a tenant alias).                                                                | Use a key from the owning account.                                                              |
| `404`  | Collection, batch, key or preview not found.                                                                      | Check the id and that it belongs to this account.                                               |
| `409`  | Conflict: duplicate `Idempotency-Key`, collection already deleting, restore after purge started, expired preview. | Read the `error` message; most are terminal for that request.                                   |
| `413`  | Image over the 30 MB encoded cap.                                                                                 | Downscale before upload.                                                                        |
| `429`  | Per-key requests-per-second or per-account concurrency exceeded.                                                  | Back off with jitter and retry. Use [batch](/docs/guides/batch-and-webhooks) for bulk work.     |
| `502`  | Engine error.                                                                                                     | Retry. The credit hold was refunded automatically.                                              |
| `503`  | Not ready (readiness probe) or a server-side key is unconfigured.                                                 | Retry later; check the [status page](/status).                                                  |

## Search with no match

A `200` from search can still mean "nothing found". The body carries `reason` and an empty `matches` array:

| `reason`             | Meaning                                                                       |
| -------------------- | ----------------------------------------------------------------------------- |
| `no_face`            | No face detected in the selfie.                                               |
| `low_quality_selfie` | A face was found but failed the quality gate.                                 |
| `point_not_found`    | `search-by-id` was given a `point_id` that does not exist in this collection. |

These are charged like any other successful call, because the model ran.

## Retrying safely

Add an `Idempotency-Key` header (any unique string, a UUID is fine) to billable calls. A retry under the same key never re-charges and never re-runs the model. See [core concepts](/docs/concepts#idempotency).

## SDK errors

The official SDKs raise typed errors for `401`, `402`, `404` and `429` and a base error for everything else, each carrying the status code and message. See [Python](/docs/sdks/python#errors) and [Node](/docs/sdks/node#errors).
