Skip to main content

Overview

All search and photo endpoints share the unified envelope { responseType, message, data } documented in Conventions. The endpoint-specific payload always lives inside data — for photo and BIB search this is images[] plus pagination; for face search and video clipping it also includes request_id and the relevant search/job state.

Shared Photo Data Shape

Photo list, BIB search, and face search responses all carry the same data payload (images[] + pagination). Face search additionally includes request_id and confidence_percentage inside data.
{
  "images": [],
  "pagination": {
    "total": 0,
    "currentPage": 0,
    "totalPages": 0,
    "hasNextPage": false,
    "hasPreviousPage": false,
    "page_size": 32
  }
}
FieldTypeDescription
imagesarrayList of ImageItem objects.
paginationobjectPaginationInfo metadata.

AllPhotosResponse

Returned by All Photos.
{
  "responseType": "success",
  "message": "Records for all images",
  "data": {
    "images": [],
    "pagination": {
      "total": 0,
      "currentPage": 0,
      "totalPages": 0,
      "hasNextPage": false,
      "hasPreviousPage": false,
      "page_size": 32
    }
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses. See Conventions.
messagestringHuman-readable status message.
data.imagesarrayList of ImageItem objects.
data.paginationobjectPaginationInfo metadata.

BibSearchResponse

Returned by BIB Search.
{
  "responseType": "success",
  "message": "Records for bib number 1234",
  "data": {
    "images": [],
    "pagination": {
      "total": 0,
      "currentPage": 0,
      "totalPages": 0,
      "hasNextPage": false,
      "hasPreviousPage": false,
      "page_size": 32
    }
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses.
messagestringHuman-readable status message.
data.imagesarrayList of ImageItem objects.
data.paginationobjectPaginationInfo metadata.

FaceSearchResponse

Returned by Face Search (both POST and GET). The request_id and confidence_percentage are nested inside data so the envelope stays uniform across all endpoints.
{
  "responseType": "success",
  "message": "Computed face search",
  "data": {
    "request_id": "ddc661a7-8861-4793-9437-af42a82d12f8",
    "confidence_percentage": 90,
    "images": [],
    "pagination": {
      "total": 0,
      "currentPage": 0,
      "totalPages": 0,
      "hasNextPage": false,
      "hasPreviousPage": false,
      "page_size": 32
    }
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses.
messagestringHuman-readable status message.
data.request_idstringRequest UUID associated with the search. See request_id idempotency.
data.confidence_percentagenumber | nullConfidence threshold used to filter face matches. May be null when no threshold is configured.
data.imagesarrayList of ImageItem objects.
data.paginationobjectPaginationInfo metadata.

TimelineDaysResponse

Returned by GET /timeline/days (see Photo Timeline). Days are ordered ascending by date and hours[] is ordered ascending by hour.
{
  "responseType": "success",
  "message": "Timeline buckets",
  "data": {
    "days": [
      {
        "date": "2024-01-01",
        "total": 125,
        "hours": [
          { "hour": 10, "count": 98 },
          { "hour": 11, "count": 27 }
        ]
      }
    ]
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses.
messagestringHuman-readable status message.
data.daysarrayList of TimelineDayItem objects.

TimelineDayItem

Each entry inside data.days[] for GET /timeline/days.
{
  "date": "2024-01-01",
  "total": 125,
  "hours": [
    { "hour": 10, "count": 98 },
    { "hour": 11, "count": 27 }
  ]
}
FieldTypeDescription
datestringUTC calendar date in YYYY-MM-DD format.
totalnumberTotal photos captured on this date.
hoursarrayList of TimelineHourBucket entries ordered by ascending hour.

TimelineHourBucket

Each entry inside data.days[].hours[] for GET /timeline/days.
{
  "hour": 10,
  "count": 98
}
FieldTypeDescription
hournumberHour of the day in UTC (023).
countnumberNumber of photos captured in this hour.

TimelineImagesResponse

Returned by GET /timeline/images (see Photo Timeline). Reuses the shared photo data shape (images[] + pagination) ordered by ascending capture timestamp.
{
  "responseType": "success",
  "message": "Records for timeline window",
  "data": {
    "images": [],
    "pagination": {
      "total": 0,
      "currentPage": 0,
      "totalPages": 0,
      "hasNextPage": false,
      "hasPreviousPage": false,
      "page_size": 32
    }
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses.
messagestringHuman-readable status message.
data.imagesarrayList of ImageItem objects.
data.paginationobjectPaginationInfo metadata.

VideoClippingStartResponse

Returned by POST /video-clipping/search-by-selfie (see Video Clipping Search). The status is always processing on success — use the GET endpoint to wait for the terminal status.
{
  "responseType": "success",
  "message": "Video clipping search started. Poll GET /api/v1/ext/{org_id}/event/{event_id}/video-clipping/{request_id} for results.",
  "data": {
    "status": "processing",
    "request_id": "ddc661a7-8861-4793-9437-af42a82d12f8"
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses.
messagestringHuman-readable status message describing what happens next.
data.statusstringAlways "processing" when the request was accepted.
data.request_idstringUUID for this video clipping search. Reuse with the GET endpoint and to download the resulting clips.

VideoClippingResultResponse

Returned by GET /video-clipping/{request_id} (see Video Clipping Search).
{
  "responseType": "success",
  "message": "Video clipping completed",
  "data": {
    "request_id": "ddc661a7-8861-4793-9437-af42a82d12f8",
    "status": "completed",
    "videos": [],
    "error": null,
    "clip_errors": []
  }
}
FieldTypeDescription
responseTypestringAlways "success" for 2xx responses.
messagestringHuman-readable status message.
data.request_idstringRequest UUID echoed from the original POST.
data.statusstringOne of processing, completed, no_matches, no_segments, clip_failed, failed.
data.videosarrayList of VideoClipItem objects. Empty until status is completed.
data.errorstring | nullTop-level error message when the job fails before any clips are generated (status failed).
data.clip_errorsarrayList of VideoClipErrorItem. Populated for clip_failed and partially-failed completed results.

VideoClipItem

Each entry inside data.videos[] returned by GET /video-clipping/{request_id} when status is completed.
{
  "uuid": "5e9a7cc1-0bcb-4a4d-b6e3-6c0b25c57a08",
  "video_url": "https://photos.9pic.ai/vids/456/motion/selfie/ddc661a7-8861-4793-9437-af42a82d12f8/5e9a7cc1-0bcb-4a4d-b6e3-6c0b25c57a08.mp4",
  "source_video_key": "12",
  "start_time": "00:00:42",
  "end_time": "00:00:52"
}
FieldTypeDescription
uuidstringUnique identifier for the generated video clip.
video_urlstringPublic URL where the clipped MP4 can be downloaded or streamed.
source_video_keystring | nullIdentifier of the configured event video source this clip was extracted from.
start_timestring | nullClip start timestamp inside the source video (HH:MM:SS).
end_timestring | nullClip end timestamp inside the source video (HH:MM:SS).

VideoClipErrorItem

Each entry inside data.clip_errors[] when the clipping service rejected one or more segments.
{
  "video_key": "34",
  "error": "Clipping service returned 500",
  "status_code": 500
}
FieldTypeDescription
video_keystring | nullIdentifier of the event video source that failed to be clipped.
errorstring | nullHuman-readable error message returned by the clipping service.
status_codenumber | nullHTTP status code returned by the clipping service, if any.

Used By

ModelEndpoint
AllPhotosResponseAll Photos
BibSearchResponseBIB Search
FaceSearchResponseFace Search (POST and GET)
TimelineDaysResponsePhoto TimelineGET /timeline/days
TimelineDayItemInside TimelineDaysResponse.data.days[]
TimelineHourBucketInside TimelineDaysResponse.data.days[].hours[]
TimelineImagesResponsePhoto TimelineGET /timeline/images
VideoClippingStartResponseVideo Clipping Search — POST
VideoClippingResultResponseVideo Clipping Search — GET
VideoClipItemInside VideoClippingResultResponse.data.videos[]
VideoClipErrorItemInside VideoClippingResultResponse.data.clip_errors[]