Skip to main content
This page documents cross-cutting rules every endpoint follows. Endpoint pages link here instead of repeating the same boilerplate. For status codes, see Errors.

Base URL

https://api.9pic.ai
All endpoints are versioned under /api/v1/ext/....

Authentication

Every request must send the API key in the X-API-Key header:
X-API-Key: <your_9pic_api_key>
Tokens are created and managed from the Developer Zone in the dashboard. See Authentication for the full workflow and token lifecycle.

Identifiers

IdentifierTypeWhere it comes from
org_idnumberShown in the top-left organisation selector at admin.9pic.ai. Must match the org the API key belongs to.
event_idnumberShown next to each event in the dashboard event list, or returned by List Events.
request_idstring (UUID)Returned by selfie-driven endpoints (Face Search — 9Pic FaceFind, Video Clipping Search — 9Pic Motion). Identifies a single search; reuse it across pagination, retries, and downloads.
image_idstring (UUID)Returned inside data.images[].image_id from photo and search endpoints. Identifies a single source photo.
bibstringThe participant’s BIB number, used by 9Pic BibTrack (BIB Search). Treated as case-insensitive on the server.

URL Path Conventions

  • Org-scoped: /api/v1/ext/{org_id}/...
  • Event-scoped: /api/v1/ext/{org_id}/event/{event_id}/...
  • Request-id-scoped: .../{request_id} where request_id is a UUID returned by a previous selfie POST.

Response Envelope

Every endpoint — success or error — returns the same three-key envelope:
{
  "responseType": "success",
  "message": "Records for all images",
  "data": {
    "images": [],
    "pagination": { "total": 0, "currentPage": 0, "totalPages": 0, "hasNextPage": false, "hasPreviousPage": false, "page_size": 32 }
  }
}
FieldTypeDescription
responseTypestring"success" on any 2xx response, "error" on any 4xx/5xx response.
messagestringHuman-readable status or error message. Safe to log; not a stable contract — never branch on its exact text.
dataobject | nullThe endpoint payload on success, null on every error. The payload schema is documented per endpoint.
This applies to every /api/v1/ext/... endpoint, including List Events, Event Details, All Photos, BIB Search, Face Search, Video Clipping Search, Download Original Photos, and Ping. Endpoint-specific fields like request_id, confidence_percentage, status, videos, pagination, etc. always live inside data.

Error envelope

Errors use the same shape with data: null:
{
  "responseType": "error",
  "message": "BIB number 1234 not found for this event",
  "data": null
}
The HTTP status code carries the error type; see Errors for the full status code table.

Datetime Format

All datetime fields are ISO 8601 strings:
2026-01-19T06:00:00
Date-only fields are not used. When a datetime field is unset, the value is null.

Pagination

Listing and search endpoints return a PaginationInfo object. Defaults and maximums vary per endpoint. See the canonical model and per-endpoint limits on Pagination Model.
Some empty-result responses return currentPage: 0 and totalPages: 0. Treat those values as “no page is available” rather than as a normal page number.

request_id Idempotency

Selfie-driven searches use a POST-once / GET-many pattern. The request_id is the canonical identifier for a single selfie search, not a session token.
ActionUse
First searchPOST /faces (or POST /video-clipping/search-by-selfie) without request_id. The server generates one and returns it.
Pagination, refresh, deep-linksGET /{request_id} reads cached results and never re-runs face matching.
Retry on POST failureRetry with the same request_id. Successful retries resolve to the cached result.
Cross-feature reuseReuse the Face Search request_id when starting Video Clipping Search, and as identifier (with method: "selfie") on Download Original Photos. One selfie upload powers all three.
A new POST with a fresh request_id (or no request_id) is treated as a brand-new billable search. Avoid issuing fresh POSTs on every page change, refresh, or component remount.
Persist request_id in URL state (for example, /results/:request_id) so refreshes and deep-links survive without re-uploading the selfie.
See Face Search and Video Clipping Search for endpoint-specific behaviour.

Async Endpoints

Video Clipping Search is asynchronous: POST returns immediately with data.status: "processing" and data.request_id. Poll GET /video-clipping/{request_id} until data.status is anything other than processing. Recommended interval: exponential backoff starting at 3s.

Host Validation

Requests are validated against an approved hostname allowlist. Calls from non-approved hosts return 403. The production allowlist includes api.9pic.ai. Talk to support if you need an additional host enabled for testing.

Error Codes

A short error table is included on every endpoint page. The full list of status codes, common causes, and recommended client behaviour lives on the Errors page.