Skip to main content
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).
{
  "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

StatusMeaning
200Success. The body is the documented response model for the endpoint.
400Validation failure. The request was rejected before any work was done.
401Authentication missing. The X-API-Key header was not provided.
403Authentication 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.
404Resource not found. The event, configuration, or request_id does not exist.
422Schema validation failure. The request body or query parameters did not match the documented model (e.g., unknown enum value, missing required field).
429Rate 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.
500Internal failure. The request could not be recorded, or async work could not be started. Safe to retry; see 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.

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).
  • 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 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, 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.
Exact rate and burst limits are tuned over time and are not published here. Contact support at hello@9pic.ai if you need the current numbers or want them raised for a specific event or campaign.
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:
{
  "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.
  • 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

StatusSafe to retry?Recommendation
400NoFix the request body and resend.
401NoAdd the X-API-Key header.
403NoFix the API key, ownership, host, or feature flag.
404SometimesA POST with a new selfie is the safest retry for an unknown request_id. Other 404s require fixing the URL.
422NoFix the request shape (enum, type, or missing field) and resend.
429YesBack off and retry with exponential delay plus jitter. Reuse the same request_id on selfie-driven endpoints so retries hit the cache.
500YesRetry with the same request_id for selfie-driven endpoints (see request_id idempotency). Use exponential backoff.
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.

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.