Skip to main content

Overview

Face Search is the API surface for 9Pic FaceFind, our AI face recognition photo search. Upload a participant’s selfie and the API returns paginated photos that match the selfie above the event’s confidence threshold. Each search is identified by a request_id (UUID). You can:
  • Omit request_id and let 9Pic generate one. The generated UUID is returned in the response so you can re-fetch the same results later without re-uploading the selfie.
  • Pass an existing request_id to retrieve cached results without re-running face matching.
Selfie/face search must be enabled for the event. Check the selfie_search flag from Event Details before calling this.

Why request_id Matters

A face search is expensive on our side and yours. Each POST /faces triggers an image upload, face matching against the event’s face index, confidence filtering, and a persisted result row. The request_id is what lets you do this work exactly once per user-intent and reuse the result everywhere else. Treat request_id as the canonical identifier for a single selfie search, not as a session token. The full idempotency model is documented in Conventions.

What problem it solves

ProblemWhat naive integrations doWhat request_id enables
User refreshes the results screenRe-upload selfie + re-run face matchingGET /faces/{request_id} returns the cached result instantly
User pages through resultsPOST again per pageOne POST, many GET /faces/{request_id}?page=N calls
Network blip on POST /facesTreat as “new search” and re-uploadRetry the same POST with the same request_id (idempotent)
Download flow needs the same matched setRe-search before downloadPass request_id as the identifier to Download Original Photos

How it optimises your system

  • Idempotent retries. If POST /faces fails partway (timeout, 5xx, dropped connection), retrying with the same request_id resolves to the cached result on success — no double-charged face-match calls and no duplicate selfie uploads.
  • Cheap pagination. Hold the request_id in your UI state. Every page change becomes a GET /faces/{request_id}?page=N&page_size=32 instead of a re-search.
  • Decouple search trigger from result rendering. Your upload screen does the POST and stashes request_id. Your results screen, share screen, and download screen all read from GET /faces/{request_id}. None of them need the selfie file.
  • Stable, shareable references. A request_id lets your backend log, audit, retry, or reconcile a specific selfie search without storing the user’s selfie image.
  • Avoid rate limiting. External API calls that perform face matching are subject to stricter limits than read-only calls. Reusing request_id shifts your traffic from POST /faces (rate-limited, billable compute) to GET /faces/{request_id} (cheap reads), keeping integrations comfortably under quota even at peak.
1

POST once

Call POST /faces with the user’s selfie. Do not pass request_id; let the server generate one. Read request_id from the response and persist it (URL state, local storage, your DB).
2

GET many

Every subsequent action that needs results (pagination, refresh, deep-link, share) calls GET /faces/{request_id}?page=N&page_size=32.
3

Retry safely

On POST failure, retry with the same request_id you intended for that selfie. The result is cached server-side once any POST succeeds.
4

Hand off to download

Pass request_id as identifier (with method: "selfie") to Download Original Photos. No new search is needed.
Persist request_id in your URL (e.g. /results/:request_id). It survives refreshes, deep-links, and share intents without re-uploading the selfie.
A new POST /faces (with a fresh request_id) is treated as a new billable face search. Avoid issuing fresh POSTs on every page change, refresh, or component remount.

Endpoints

POST /api/v1/ext/{org_id}/event/{event_id}/faces
GET  /api/v1/ext/{org_id}/event/{event_id}/faces/{request_id}

POST /faces — Upload a Selfie

Uploads a selfie image and returns the matching event photos.

Path Parameters

ParameterTypeRequiredDescription
org_idnumberYesYour organisation ID.
event_idnumberYesThe event to search within.

Query Parameters

ParameterTypeRequiredDescription
pagenumberNoPage number (default: 1).
page_sizenumberNoImages per page (default: 32, max: 100).
Results are paginated. See the Pagination Model.

Multipart Form Fields

FieldTypeRequiredDescription
filefileYesSelfie image (JPEG/PNG, max 5 MB recommended).
request_idstringNoUUID. If omitted, 9Pic generates one and returns it in the response.

Example Request

curl -i \
  -H "X-API-Key: <your_9pic_api_key>" \
  -F "file=@selfie.jpg" \
  "https://api.9pic.ai/api/v1/ext/903/event/456/faces?page=1&page_size=32"
To reuse an existing request_id, add -F "request_id=<uuid>" (cURL), include it in data={"request_id": "<uuid>"} (Python), or formData.append("request_id", "<uuid>") (JavaScript).

Example Response

{
  "responseType": "success",
  "message": "Computed face search",
  "data": {
    "request_id": "ddc661a7-8861-4793-9437-af42a82d12f8",
    "confidence_percentage": 90,
    "images": [
      {
        "img_url": "https://photos.9pic.ai/imgs/456/large/a4402318-0cf4-4e1e-b8e8-ac8e8f2fc244.jpg",
        "height": 4860,
        "width": 3240,
        "image_id": "a4402318-0cf4-4e1e-b8e8-ac8e8f2fc244",
        "thumbnail_url": "https://photos.9pic.ai/imgs/456/small/a4402318-0cf4-4e1e-b8e8-ac8e8f2fc244.jpg",
        "original_url": null
      }
    ],
    "pagination": {
      "total": 12,
      "currentPage": 1,
      "totalPages": 1,
      "hasNextPage": false,
      "hasPreviousPage": false,
      "page_size": 32
    }
  }
}
Returns the cached result for a previous selfie search using its request_id. Useful for paging through results or refreshing a UI without re-uploading the selfie.

Path Parameters

ParameterTypeRequiredDescription
org_idnumberYesYour organisation ID.
event_idnumberYesThe event the search belongs to.
request_idstringYesUUID returned by a previous POST /faces call.

Query Parameters

ParameterTypeRequiredDescription
pagenumberNoPage number (default: 1).
page_sizenumberNoImages per page (default: 32, max: 100).
Results are paginated. See the Pagination Model.

Example Request

curl -i \
  -H "X-API-Key: <your_9pic_api_key>" \
  "https://api.9pic.ai/api/v1/ext/903/event/456/faces/ddc661a7-8861-4793-9437-af42a82d12f8?page=2&page_size=32"

Example Response

The response shape is identical to POST /faces. Use the same model and the same Matches Found / No Matches payloads above.

Response Models

ModelDescription
FaceSearchResponseTop-level face search response envelope.
ImageItemImage object returned inside data.images[].
PaginationInfoPagination metadata returned inside data.pagination.
original_url is null in the standard face search response.
Use the request_id from this response with Download Original Photos (method: "selfie") to fetch presigned download links for the matched originals.

Error Responses

StatusMeaning
400request_id is not a valid UUID, or the uploaded selfie file is empty.
401API key is missing.
403API key is invalid, inactive, token/event ownership mismatch, or selfie search is disabled for this event.
404Event configuration not found, or request_id is unknown (GET only).
429Rate limit exceeded. Back off and retry with the same request_id to hit the cache.
500Internal failure that prevented the request from being recorded.
See Errors for canonical descriptions and retry guidance.