---
title: "Get an asset"
method: GET
path: "/api/assets/{asset_id}"
tags: ["assets"]
---

# Get an asset

`GET /api/assets/{asset_id}`

Fetches one asset and its associated metadata by ID. Use this when you already have a specific asset ID (e.g., from `list_assets`, `search_assets`, or `list_album_assets`) and need its full details. For bulk fetch of multiple known IDs, prefer `list_assets` with the `ids` parameter to avoid N round trips. `asset_urls` are signed URLs for client rendering only; to visually inspect the image pixels, call `view_asset` instead.

## Path parameters

- `asset_id` string, required — Asset ID (with `asset_` prefix) to fetch.

## Query parameters

- `include` string[], nullable — Opt-in expansion fields. Supported values: `metadata` (camera/EXIF/GPS and location names), `faces`, `people`, `metrics` (ML quality scores), `file_data` (a group token populating the nested `file_data` object with the file/provenance scalars `device_asset_id`, `device_id`, `file_created_at`, `file_modified_at`, `checksum`, `checksum_sha1`, `file_size_bytes`), and `variants` (every `asset_urls` rung beyond the lean one. Without it `asset_urls` carries only its lean rung — `thumbnail` for an image, or `thumbnail_image` for a video — so callers that render non-thumbnail variants or download the current rendering must pass it). Accepts multiple `include=` query params or a single comma-delimited value (e.g. `include=faces,people`). Unknown values return 422. When omitted, only the lean core is returned (`id`, `mime_type`, `local_datetime`, dimensions, `description`, `thumbhash`, `asset_urls`, `kind`, `current_version_id`) and each data field above is null/absent until you request it.

## Response `200`

Successful Response

- AssetResponse — Represents a photo or video asset with metadata and access URLs. Top-level fields describe the asset's current rendering (the version identified by `current_version_id`) unless they explicitly name the original upload, like `original_file_name` and the `file_data` group.
  - `id` string, required — Unique asset identifier with 'asset_' prefix
  - `mime_type` string, required — MIME type of the current rendering (e.g., 'image/jpeg', 'video/mp4').
  - `original_file_name` string, required — Filename the asset was uploaded under.
  - `local_datetime` string, date-time, required — When the photo/video was taken, in the device's local timezone
  - `file_data` FileDataResponse — File/provenance scalars describing the uploaded *file* (not its content). Returned only when requested via ``include=file_data``; the whole object is ``null`` otherwise. When present, every field carries its real value — ``checksum_sha1`` is the lone exception (``null`` for legacy rows that never had a SHA-1). This nested object is the home for the file/provenance group.
    - `device_asset_id` string, required — Original asset identifier from the device that uploaded this asset.
    - `device_id` string, required — Identifier of the device that uploaded this asset.
    - `file_created_at` string, date-time, required — When the file was created on the uploading device.
    - `file_modified_at` string, date-time, required — When the file was last modified on the uploading device.
    - `checksum` string, required — Base64-encoded SHA-256 hash of the asset contents for duplicate detection and integrity.
    - `checksum_sha1` string, nullable — Base64-encoded SHA-1 hash of the asset contents. `null` for older assets that have no SHA-1.
    - `file_size_bytes` integer, required — Size of the uploaded file in bytes. Each rendering's own size is on its row in the asset's version listing.
  - `created_at` string, date-time, required — When this asset record was created in the database
  - `updated_at` string, date-time, required — When this asset record was last updated
  - `metadata` MetadataResponse — Metadata for an asset — camera/EXIF fields, GPS, and location names.
    - `asset_id` string, required — ID of the asset this metadata belongs to
    - `created_at` string, date-time, required — When this metadata record was created
    - `updated_at` string, date-time, required — When this metadata record was last updated
    - `make` string, nullable — Camera manufacturer (e.g., 'Canon', 'Nikon')
    - `model` string, nullable — Camera model (e.g., 'EOS 5D Mark IV')
    - `orientation` integer, nullable — Image orientation value (1-8) indicating rotation/flip: 1=normal, 2=mirror horizontal, 3=rotate 180°, 4=mirror vertical, 5=mirror horizontal+rotate 90° CW, 6=rotate 90° CW, 7=mirror horizontal+rotate 90° CCW, 8=rotate 90° CCW
    - `raw_width` integer, nullable — Pre-rotation raw width; null when not available
    - `raw_height` integer, nullable — Pre-rotation raw height; null when not available
    - `modified_datetime` string, date-time, nullable — When the file was last modified, with timezone offset if available
    - `original_datetime` string, date-time, nullable — When the photo was originally taken, with timezone offset if available
    - `digitized_datetime` string, date-time, nullable — When the photo was digitized, with timezone offset if available
    - `lens_model` string, nullable — Lens model used (e.g., 'EF 24-70mm f/2.8L II USM')
    - `f_number` number, nullable — Aperture f-stop value (e.g., 2.8, 5.6)
    - `focal_length` number, nullable — Focal length in millimeters
    - `iso` integer, nullable — ISO sensitivity value (e.g., 100, 800, 3200)
    - `exposure_time` number, nullable — Shutter speed in seconds (e.g., 0.001 for 1/1000s)
    - `exposure_bias` number, nullable — Exposure compensation in EV (e.g., -1.0, +0.5)
    - `latitude` number, nullable — GPS latitude in decimal degrees
    - `longitude` number, nullable — GPS longitude in decimal degrees
    - `altitude` number, nullable — GPS altitude in meters
    - `city` string, nullable — City name
    - `state` string, nullable — State/province name
    - `country` string, nullable — Country name
    - `country_code` string, nullable — ISO 3166-1 alpha-2 country code (e.g., 'US', 'JP')
    - `sublocation` string, nullable — Neighborhood or district
    - `place_name` string, nullable — Landmark or point-of-interest name
    - `timezone` string, nullable — IANA timezone identifier (e.g., 'America/Los_Angeles')
    - `display_label` string, nullable — Human-readable location label. Picks the most specific available identifier (place_name > sublocation > city > country) and appends broader context (city, then state-or-country). Example: 'Golden Gate Bridge, San Francisco, California'. Null when no location fields are populated.
    - `description` string, nullable — Image description or caption
    - `fps` number, nullable — Frame rate for video files
    - `live_photo_cid` string, nullable — Live photo content identifier
    - `projection_type` string, nullable — Projection type (e.g., for 360° photos)
    - `auto_stack_id` string, nullable — Identifier for automatic photo stacking
    - `rating` integer, nullable — User or camera rating (typically 1-5 stars)
  - `metrics` object, nullable — ML-generated quality scores and other metrics. `null` when not requested via `include=metrics`.
  - `asset_urls` object, nullable — Named asset variants. Images: 'original', 'thumbnail', 'small', 'preview', 'fullsize'. Videos: 'original', plus 'thumbnail_image', 'small_image', 'preview_image', 'fullsize_image' pointing at the extracted still. 'original' is served with a Content-Disposition attachment header (signed 'dl' filename param) so a top-level navigation saves it to disk, while inline subresource loads (<video>, fetch) still render it. Variant URLs are stable: a derived variant may briefly 404 until its artifact is generated, then serve from the same URL.
  - `description` string, nullable — AI-generated description of the asset's content, quality, and composition. null means description generation has not yet run; empty string means the model refused to describe the asset. Distinct from metadata.description (camera-embedded EXIF metadata).
  - `thumbhash` string, nullable — Base64-encoded ThumbHash placeholder (~28 chars). Clients decode with the `thumbhash` library (JS / Swift / Kotlin) to render an instant blurred preview before the CDN thumbnail arrives. `null` while generation is pending.
  - `faces` FaceResponse[], nullable — All faces detected in this asset. `null` when not requested via `include=faces`; `[]` when requested but the asset has no 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).
  - `people` PersonResponse[], nullable — All unique people identified in this asset (deduplicated from faces). `null` when not requested via `include=people`; `[]` when requested but none are identified.
    - `id` string, required — Unique person identifier with 'person_' prefix
    - `name` string, nullable — Optional name assigned to this person
    - `birth_date` string, date, nullable — Optional birth date of this person
    - `is_hidden` boolean, required — Whether this person should be hidden from the UI
    - `is_favorite` boolean, required — Whether this person is marked as a favorite
    - `asset_count` integer, nullable — Number of unique photos this person appears in, or null if not computed
    - `thumbnail_face_id` string, nullable — ID of the face resource used as this person's thumbnail
    - `asset_urls` object, nullable — Asset variants from this person's thumbnail face. May be null when embedded in an AssetResponse; use /api/people endpoints for full person data.
    - `cluster_metrics` ClusterMetricsResponse — Cohesion metrics for a Person's face cluster — surfaced via ``include=cluster_metrics`` on the people endpoints. These describe how tight the cluster is in embedding space (lower = more cohesive) and drive both the production face-assignment cohesion gate and the operator-facing face cleanup dashboard.
      - `pairwise_p90` number, required — 90th-percentile pairwise cosine distance between faces in this person's cluster. Lower = more cohesive cluster; loose clusters (higher pairwise_p90) are gated out of the face-assignment path to prevent further drift.
      - `pairwise_mean` number, required — Mean pairwise cosine distance between faces in this person's cluster.
      - `face_count` integer, required — Number of faces that fed into the centroid and pairwise metrics. This is the cluster-membership count, **not** the same as `asset_count` — `face_count` counts every face row, while `asset_count` counts distinct assets (one asset can contribute multiple faces of the same person).
    - `created_at` string, date-time, required — When this person record was created
    - `updated_at` string, date-time, required — When this person record was last updated
  - `kind` string, required — What produced the current rendering: `original` (the upload), `edit` (a client-baked edit), or `external:<service>`. The namespace is open — derive edited-ness as `kind != "original"`.
  - `current_version_id` string, required — ID (`asset_version_` prefix) of the current version, which the top-level rendering fields describe. Pass it as the expected current version on version writes so a racing write is rejected.
  - `width` integer — Width of the current rendering in pixels.
  - `height` integer — Height of the current rendering in pixels.
  - `duration` number, nullable — Video length in seconds. `null` for images and for videos whose duration has not been extracted yet.
  - `trashed_at` string, date-time, nullable — When this asset was moved to trash (ISO 8601, UTC). `null` for live assets. Trashed assets are excluded from default list/search results and are purged after the configured retention window.
  - `stack_id` string, nullable — ID of the stack this asset belongs to (`asset_stack_` prefix), or `null` when the asset is not part of a stack. Group assets by this value to collapse a stack into a single tile; the stack's own cover and member count are not carried on the asset. Distinct from `metadata.auto_stack_id`, which is the camera's in-EXIF `MakerNotes:AutoStackID` string — this is the server-assigned foreign key to the asset's stack.

## 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)
