---
title: "List face detections"
method: GET
path: "/api/faces"
tags: ["faces"]
---

# List face detections

`GET /api/faces`

Returns a paginated list of individual face detections (with bounding boxes), ordered by creation time (newest first), optionally filtered by asset, person, or ID. Each row is a single face in a single asset — a person with many photos will have many face rows.

**Use `list_people` instead** when the user wants the grouped identities ('list everyone in my library') rather than individual face detections. This tool is useful for curating clustering results, finding unassigned faces, or picking a thumbnail face for a person via `update_person.thumbnail_face_id`.

**Pagination** is cursor-based: when `has_more` is true, pass the `id` of the last face in `data` as `starting_after_id` to fetch the next page.

## Query parameters

- `asset_id` string, nullable — Return only faces detected in this asset. Useful for 'show me all the faces in this photo'.
- `person_id` string, nullable — Return only faces currently assigned to this person. Useful for reviewing or curating a person's face cluster.
- `ids` string[], nullable — Look up specific faces by ID (max 200). IDs use the `face_` prefix. Accepts multiple `ids=` query params or a single comma-delimited value (e.g., `ids=face_1,face_2`).
- `limit` integer — Maximum number of faces per page (1–200). Defaults to 20.
- `starting_after_id` string, nullable — Cursor for pagination. Pass the `id` of the last face in the previous response's `data` to fetch the next page. Omit for the first page.
- `library_id` string, nullable — Library to list from. Optional if the user has a single live (non-trashed) library; required when they have multiple.
- `include` string[], nullable — Opt-in expansion fields. Supported values: `cluster_assignment` (adds the nested `cluster_assignment` object — `distance_to_person` and a top-K `candidates` list of nearby Persons). Accepts multiple `include=` query params or a single comma-delimited value (e.g., `include=cluster_assignment`).

## Response `200`

Successful Response

- PaginatedFacesResponse
  - `data` FaceResponse[], required — List of faces
    - `id` string, required — Unique face identifier with 'face_' prefix
    - `asset_id` string, required — ID of the asset containing this face
    - `person_id` string, nullable — ID of the person this face belongs to (if identified)
    - `bounding_box` object, required — Face location as {x, y, w, h} coordinates in pixels
    - `confidence` number, nullable — Detector confidence on a 0-1 scale; higher is more confident among faces detected under the same configuration (values are not comparable across detector generations). Null on legacy faces without a stored score and on manually added faces.
    - `source` 'automatic' | 'manual', required — How this face was added: 'automatic' for detector-found faces, 'manual' for user-drawn face boxes.
    - `timestamp_ms` integer, nullable — For video files, timestamp in milliseconds when face appears
    - `asset_urls` object, nullable — Asset variants for this face: 'thumbnail' with face crop
    - `created_at` string, date-time, required — When this face was detected and recorded
    - `updated_at` string, date-time, required — When this face record was last updated
    - `cluster_assignment` ClusterAssignmentResponse — Per-face cluster-assignment diagnostics: how well the face fits its currently-assigned Person, and which other Persons are nearby in embedding space. Surfaced via ``include=cluster_assignment`` on the faces endpoints — used by the operator-facing face cleanup dashboard to triage mis-clustered faces.
      - `distance_to_person` number, nullable — Cosine distance from the face's embedding to its currently-assigned Person's centroid. Lower = better fit. Null when the face is unassigned or when the assigned Person has no centroid.
      - `candidates` FaceCandidatePersonResponse[] — Persons in the same library that pass the same gate shape as production face assignment, surfaced with deliberately relaxed thresholds so the list is a superset of what the automated path would admit. Sorted ascending by distance. Excludes the face's currently-assigned Person (its distance is in `distance_to_person`). Empty when no eligible Persons pass the gate.
        - `person_id` string, required — Person ID (with 'person_' prefix) of the candidate.
        - `name` string, nullable — Display name of the candidate Person, or null for unnamed clusters. Candidates surface the same Persons production assignment considers, which includes unnamed clusters.
        - `distance` number, required — Cosine distance from the face's embedding to this Person's centroid (lower = closer).
  - `has_more` boolean, required — True if there are more faces after this page. Pass the last face's `id` as `starting_after_id` to fetch the next page.

## Other responses

- `401` — Missing, invalid, or expired credentials.
- `403` — The credentials are valid but not authorized for this operation — for example an API key whose action or library scope excludes it, or a credential type this operation does not accept.
- `404` — Not found
- `422` — Validation Error
- `429` — Rate limit exceeded. Retry after the interval in the `Retry-After` header.

---

[API](https://skmtc.net/gumnut-ai/apis/gumnut-api.md) · [All operations](https://skmtc.net/gumnut-ai/apis/gumnut-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/gumnut-ai/gumnut-api/versions/e71db45f5d4a/schema)
