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

# Errors

> Status codes, common causes, and recommended client behaviour for every 9Pic API endpoint

The 9Pic API uses standard HTTP status codes. Endpoint pages list which subset of these codes apply to that endpoint, and link here for the full description.

## Error Envelope

Every error response uses the same three-key envelope as success responses, with `responseType: "error"` and `data: null`. The HTTP status code carries the error type; the `message` is a short human-readable description (safe to log, not stable enough to branch on).

```json theme={null}
{
  "responseType": "error",
  "message": "BIB number 1234 not found for this event",
  "data": null
}
```

`422 Unprocessable Entity` errors (request validation failures) flatten Pydantic field errors into a single `message` string of the form `field.path: error description; field.path: error description`. The HTTP status remains `422`.

## Status Codes

| Status | Meaning                                                                                                                                                                                                                                 |
| ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `200`  | Success. The body is the documented response model for the endpoint.                                                                                                                                                                    |
| `400`  | Validation failure. The request was rejected before any work was done.                                                                                                                                                                  |
| `401`  | Authentication missing. The `X-API-Key` header was not provided.                                                                                                                                                                        |
| `403`  | Authentication or authorisation failure. The key is invalid/inactive, the path identifiers do not belong to this org, the host is not approved, or the requested feature is disabled for this event.                                    |
| `404`  | Resource not found. The event, configuration, or `request_id` does not exist.                                                                                                                                                           |
| `422`  | Schema validation failure. The request body or query parameters did not match the documented model (e.g., unknown enum value, missing required field).                                                                                  |
| `429`  | Rate limit exceeded. The platform-wide API Gateway throttle has been hit across the `/api/v1/ext/...` surface. Safe to retry with exponential backoff. Contact support for the exact rate and burst limits applied to your integration. |
| `500`  | Internal failure. The request could not be recorded, or async work could not be started. Safe to retry; see [retry guidance](#retry-guidance) below.                                                                                    |

## 400 — Bad Request

Returned when the request itself is malformed. Common causes:

* The uploaded selfie file is empty (multipart endpoints).
* `request_id` was provided but is not a valid UUID.
* Path or query parameters fail Pydantic validation (for example, `page=0` or `page_size > max`).
* Missing or malformed JSON body on POST endpoints that require it.

A 400 means no billable work happened. Fix the request and resend it.

## 401 — Unauthorized

Returned when the `X-API-Key` header is missing entirely. Add the header and retry. See [Authentication](/api-reference/authentication).

## 403 — Forbidden

Returned for any of the following:

* The API key is unknown, inactive, or has been deleted.
* The `org_id` in the URL does not belong to the API key.
* The `event_id` in the URL does not belong to the `org_id`.
* The request originated from a host that is not on the allowlist (see [Host Validation](/api-reference/conventions#host-validation)).
* The endpoint requires an event-level feature flag (`bib_search`, `selfie_search`, `video_search`, `video_selfie_search`) that is currently `false` for this event. Check the flags from [Event Details](/api-reference/event-details) before calling search endpoints.

A 403 will not become a 200 by retrying. Fix the underlying configuration first.

## 404 — Not Found

Returned when:

* The event does not exist or its memories configuration is missing.
* A `request_id`-scoped GET is called with an unknown UUID. This typically means no `POST` has been made for that UUID, or the search record was rotated out.
* A BIB number does not exist for the event. (Some endpoints return a `200` with an empty `images[]` array instead — see the endpoint page for which behaviour applies.)

## 422 — Unprocessable Entity

Returned when the request body or query parameters fail Pydantic schema validation. Common causes:

* Unknown value for an enum field (for example, `method: "qr"` on [Download Original Photos](/api-reference/download-original-photos), which only accepts `"bib"` or `"selfie"`).
* A required field is missing from the JSON body.
* A field is the wrong type (for example, `identifier` sent as a number instead of a string).

The `message` flattens all per-field errors into a single string. Fix the request and resend.

## 429 — Too Many Requests

Returned when API Gateway throttling kicks in. The 9Pic API is fronted by an AWS API Gateway stage with a sustained-rate limit and a burst capacity applied across the entire `/api/v1/ext/...` surface — every client, every key, and every endpoint share the same token bucket.

<Note>
  Exact rate and burst limits are tuned over time and are not published here. Contact support at [hello@9pic.ai](mailto:hello@9pic.ai) if you need the current numbers or want them raised for a specific event or campaign.
</Note>

Unlike other errors, `429` responses are returned by API Gateway **before** the request reaches the application layer. The body therefore does **not** match the unified `{ responseType, message, data }` envelope. Expect a minimal payload such as:

```json theme={null}
{
  "message": "Too Many Requests"
}
```

Recommended client behaviour:

* Treat `429` as transient and always retryable.
* Use exponential backoff with jitter (for example, start at 500 ms, double up to a cap of 30 s, add ±25% jitter).
* Reuse the same `request_id` on selfie-driven endpoints. Successful retries resolve to the cached result, so you do not pay for the same search twice — see [request\_id idempotency](/api-reference/conventions#request-id-idempotency).
* If you sustain bursts above the platform limit (for example, opening the search to large simultaneous audiences), reach out to support so we can review the throttle profile for your integration.

## 500 — Internal Server Error

Returned when the API could not record the request or start an async job. Examples:

* Database write failed before the request could be persisted.
* An async pipeline (for example, video clipping) could not be enqueued.

For video clipping, when the async job itself fails after the POST has been accepted, the GET endpoint will still return `200` with `data.status: "failed"` and `data.error: "<reason>"`. The selfie record is marked `failed`, and a fresh `POST` is the safest retry path. See [retry guidance](#retry-guidance).

## Retry Guidance

| Status | Safe to retry? | Recommendation                                                                                                                                                                |
| ------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | No             | Fix the request body and resend.                                                                                                                                              |
| `401`  | No             | Add the `X-API-Key` header.                                                                                                                                                   |
| `403`  | No             | Fix the API key, ownership, host, or feature flag.                                                                                                                            |
| `404`  | Sometimes      | A POST with a new selfie is the safest retry for an unknown `request_id`. Other 404s require fixing the URL.                                                                  |
| `422`  | No             | Fix the request shape (enum, type, or missing field) and resend.                                                                                                              |
| `429`  | Yes            | Back off and retry with exponential delay plus jitter. Reuse the same `request_id` on selfie-driven endpoints so retries hit the cache.                                       |
| `500`  | Yes            | Retry with the **same** `request_id` for selfie-driven endpoints (see [request\_id idempotency](/api-reference/conventions#request-id-idempotency)). Use exponential backoff. |

<Tip>
  Selfie-driven endpoints are designed to be retried with the same `request_id`. Successful retries resolve to the cached result, so you do not pay twice for the same search.
</Tip>

## Endpoint-Specific Errors

Each endpoint page includes a short table listing only the codes that apply to that endpoint. Use this page for the canonical descriptions; use the endpoint page for which subset to expect.
