> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gumnut.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Read coherent domain projections

> Read an explicit bounded set of roots and their complete dependencies from one current read-only source snapshot. Only the gumnut-library version 1 roots profile is supported. Results are all-or-error.



## OpenAPI

````yaml https://api.gumnut.ai/openapi.json post /api/sync/projection-reads
openapi: 3.1.0
info:
  title: Gumnut API
  description: >-
    The Gumnut API manages photo and video libraries: upload and organize
    assets, search by content, group detected faces into people, and curate
    albums and stacks.


    Headless clients authenticate by sending either a Gumnut API key
    (`apikey_...`) or an OAuth access token as a Bearer token in the
    `Authorization` header. The Gumnut web and mobile apps sign in with a
    first-party session (Clerk session JWT) instead, which is also the only
    credential that can manage API keys and library sharing.
  contact:
    name: Gumnut
    url: https://www.gumnut.ai/contact
  version: 1.0.0
servers:
  - url: https://api.gumnut.ai
    description: Production
security:
  - apiKeyAuth: []
  - oauthJwtAuth: []
tags:
  - name: assets
    description: >-
      Photos and videos in a library: upload, list and filter, update metadata,
      trash and restore.
  - name: search
    description: >-
      Content-based search over a library's assets, with album, person, date,
      and location filters.
  - name: albums
    description: User-curated collections of assets.
  - name: album-assets
    description: Link records connecting albums to their member assets.
  - name: stacks
    description: >-
      Groups of related shots of the same moment, presented as a single unit
      with a cover asset.
  - name: people
    description: Named people, each built from clustered faces.
  - name: faces
    description: Detected faces and their assignment to people.
  - name: libraries
    description: Top-level containers that own assets, albums, people, and everything else.
  - name: library-invitations
    description: First-party invitation management and admission for photo libraries.
  - name: events
    description: Change-event feed for keeping client state in sync.
  - name: sync
    description: Coherent current domain projections for library synchronization.
  - name: tasks
    description: Status of background processing tasks.
  - name: users
    description: The authenticated user's profile.
  - name: api-keys
    description: >-
      Create and manage Gumnut API keys. Requires a first-party Gumnut app
      session — API keys and OAuth tokens cannot manage credentials.
  - name: oauth
    description: OAuth flow endpoints for obtaining and refreshing access tokens.
  - name: feedback
    description: Reports of friction using Gumnut.
  - name: server
    description: Service health.
paths:
  /api/sync/projection-reads:
    post:
      tags:
        - sync
      summary: Read coherent domain projections
      description: >-
        Read an explicit bounded set of roots and their complete dependencies
        from one current read-only source snapshot. Only the gumnut-library
        version 1 roots profile is supported. Results are all-or-error.
      operationId: read_projections
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProjectionReadRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectionReadResponse'
        '401':
          description: Missing, invalid, or expired credentials.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: >-
            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.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '409':
          description: >-
            Conflict Clerk sign-in could not be associated with the existing
            account. Resolve the identity conflict before retrying sign-in;
            repeated requests with unchanged verification and identity state
            will not resolve it.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/ErrorResponse'
                  - $ref: '#/components/schemas/ProjectionErrorResponse'
        '413':
          description: Content Too Large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectionErrorResponse'
        '422':
          description: Unprocessable Content
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectionErrorResponse'
        '429':
          description: >-
            Rate limit exceeded, or too many of your requests are already in
            progress. Retry after the interval in the `Retry-After` header.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: '#/components/schemas/ErrorResponse'
                  - $ref: '#/components/schemas/ProjectionErrorResponse'
components:
  schemas:
    ProjectionReadRequest:
      properties:
        mode:
          type: string
          const: roots
          title: Mode
          description: Read exactly the explicit roots and their required dependencies
        library_id:
          type: string
          maxLength: 255
          minLength: 1
          title: Library Id
          description: Explicit live library binding for every root and dependency
        profile:
          $ref: '#/components/schemas/ProjectionProfile'
          description: Versioned source semantics to project
        keys:
          items:
            $ref: '#/components/schemas/ProjectionKey'
          type: array
          maxItems: 100
          minItems: 1
          title: Keys
          description: Nonempty unique root selection; exceeding capacity returns 413
      additionalProperties: false
      type: object
      required:
        - mode
        - library_id
        - profile
        - keys
      title: ProjectionReadRequest
    ProjectionReadResponse:
      properties:
        semantic_schema_version:
          type: integer
          const: 1
          title: Semantic Schema Version
          description: Projection bundle semantic schema version
        snapshot_id:
          type: string
          format: uuid
          title: Snapshot Id
          description: Diagnostic read identifier; cannot retrieve an old snapshot
        profile_hash:
          type: string
          title: Profile Hash
          description: Lowercase SHA-256 of the canonical complete semantic manifest
        scope:
          $ref: '#/components/schemas/GumnutProjectionScope'
          description: Current library scope captured with the content
        roots:
          items:
            $ref: '#/components/schemas/ProjectionRootResult'
          type: array
          title: Roots
          description: Exact selected root results, sorted by kind and stable key
        projections:
          items:
            $ref: '#/components/schemas/TypedProjection'
          type: array
          title: Projections
          description: >-
            Deduplicated complete transitive closure, sorted by kind and stable
            key, including the principal
        baseline_start:
          type: 'null'
          title: Baseline Start
          description: Null for explicit roots reads
        enumeration:
          type: 'null'
          title: Enumeration
          description: Null for explicit roots reads
      additionalProperties: false
      type: object
      required:
        - semantic_schema_version
        - snapshot_id
        - profile_hash
        - scope
        - roots
        - projections
        - baseline_start
        - enumeration
      title: ProjectionReadResponse
    ErrorResponse:
      title: ErrorResponse
      type: object
      properties:
        detail:
          title: Detail
          type: string
          description: Human-readable explanation of the error.
      required:
        - detail
    ProjectionErrorResponse:
      properties:
        detail:
          $ref: '#/components/schemas/ProjectionErrorDetail'
          description: Structured projection failure with no partial bundle
      additionalProperties: false
      type: object
      required:
        - detail
      title: ProjectionErrorResponse
    ProjectionProfile:
      properties:
        name:
          type: string
          const: gumnut-library
          title: Name
          description: Immutable Gumnut domain contract name
        version:
          type: integer
          const: 1
          title: Version
          description: Immutable contract version
      additionalProperties: false
      type: object
      required:
        - name
        - version
      title: ProjectionProfile
    ProjectionKey:
      oneOf:
        - $ref: '#/components/schemas/EntityProjectionKey'
        - $ref: '#/components/schemas/AlbumAssetProjectionKey'
      discriminator:
        propertyName: kind
        mapping:
          album: '#/components/schemas/EntityProjectionKey'
          album_asset: '#/components/schemas/AlbumAssetProjectionKey'
          asset: '#/components/schemas/EntityProjectionKey'
          current_user: '#/components/schemas/EntityProjectionKey'
          face: '#/components/schemas/EntityProjectionKey'
          person: '#/components/schemas/EntityProjectionKey'
          stack: '#/components/schemas/EntityProjectionKey'
    GumnutProjectionScope:
      properties:
        library_id:
          type: string
          title: Library Id
          description: Current bound library identifier
        library:
          $ref: '#/components/schemas/LibraryResponse'
          description: >-
            Current actual library owner, caller role, counts, limits, and
            profile
        policy_fingerprint:
          type: string
          title: Policy Fingerprint
          description: >-
            Opaque source eligibility policy fingerprint; a changed value
            requires coverage rebuild
      additionalProperties: false
      type: object
      required:
        - library_id
        - library
        - policy_fingerprint
      title: GumnutProjectionScope
    ProjectionRootResult:
      properties:
        key:
          $ref: '#/components/schemas/ProjectionKey'
          description: Exactly one of the selected root keys
        status:
          type: string
          enum:
            - present
            - absent
            - not_projected
          title: Status
          description: >-
            Present, absent from this library, or excluded by profile
            eligibility
      additionalProperties: false
      type: object
      required:
        - key
        - status
      title: ProjectionRootResult
    TypedProjection:
      oneOf:
        - $ref: '#/components/schemas/CurrentUserProjection'
        - $ref: '#/components/schemas/AssetProjection'
        - $ref: '#/components/schemas/PersonProjection'
        - $ref: '#/components/schemas/FaceProjection'
        - $ref: '#/components/schemas/StackProjection'
        - $ref: '#/components/schemas/AlbumProjection'
        - $ref: '#/components/schemas/AlbumAssetProjection'
      discriminator:
        propertyName: kind
        mapping:
          album: '#/components/schemas/AlbumProjection'
          album_asset: '#/components/schemas/AlbumAssetProjection'
          asset: '#/components/schemas/AssetProjection'
          current_user: '#/components/schemas/CurrentUserProjection'
          face: '#/components/schemas/FaceProjection'
          person: '#/components/schemas/PersonProjection'
          stack: '#/components/schemas/StackProjection'
    ProjectionErrorDetail:
      properties:
        code:
          type: string
          title: Code
          description: Stable machine-readable projection error code
        message:
          type: string
          title: Message
          description: Safe server-owned explanation
        retryable:
          type: boolean
          title: Retryable
          description: Whether retrying a fresh read without changing input may succeed
        limit:
          anyOf:
            - type: string
              enum:
                - roots
                - projections
                - bytes
                - snapshot_ms
            - type: 'null'
          title: Limit
      additionalProperties: false
      type: object
      required:
        - code
        - message
        - retryable
      title: ProjectionErrorDetail
    EntityProjectionKey:
      properties:
        kind:
          type: string
          enum:
            - current_user
            - asset
            - person
            - face
            - stack
            - album
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: EntityProjectionKey
    AlbumAssetProjectionKey:
      properties:
        kind:
          type: string
          const: album_asset
          title: Kind
        album_id:
          type: string
          maxLength: 255
          minLength: 1
          title: Album Id
          description: Album identifier in the bound library
        asset_id:
          type: string
          maxLength: 255
          minLength: 1
          title: Asset Id
          description: Asset identifier in the bound library
      additionalProperties: false
      type: object
      required:
        - kind
        - album_id
        - asset_id
      title: AlbumAssetProjectionKey
    LibraryResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique library identifier with 'lib_' prefix
        name:
          type: string
          title: Name
          description: Display name of the library
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: Optional description text for the library
        user_id:
          type: string
          title: User Id
          description: ID of the user who owns this library
        owner:
          $ref: '#/components/schemas/UserSummary'
        role:
          type: string
          enum:
            - owner
            - viewer
            - collaborator
          title: Role
        asset_count:
          type: integer
          title: Asset Count
          description: Total number of assets in this library
        storage_used_bytes:
          type: integer
          title: Storage Used Bytes
          description: Bytes of assets currently stored in this library
        storage_limit_bytes:
          anyOf:
            - type: integer
            - type: 'null'
          title: Storage Limit Bytes
          description: >-
            Maximum bytes this library may store, or null if no per-library
            limit applies
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this library was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this library was last updated
      type: object
      required:
        - id
        - name
        - user_id
        - owner
        - role
        - asset_count
        - storage_used_bytes
        - created_at
        - updated_at
      title: LibraryResponse
      description: Represents a user's photo library.
    CurrentUserProjection:
      properties:
        kind:
          type: string
          const: current_user
          title: Kind
        key:
          $ref: '#/components/schemas/CurrentUserProjectionKey'
          description: Stable key matching this projection value
        value:
          $ref: '#/components/schemas/UserResponse'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: CurrentUserProjection
    AssetProjection:
      properties:
        kind:
          type: string
          const: asset
          title: Kind
        key:
          $ref: '#/components/schemas/AssetProjectionKey'
          description: Stable key matching this projection value
        value:
          $ref: '#/components/schemas/AssetResponse'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: AssetProjection
    PersonProjection:
      properties:
        kind:
          type: string
          const: person
          title: Kind
        key:
          $ref: '#/components/schemas/PersonProjectionKey'
          description: Stable key matching this projection value
        value:
          $ref: '#/components/schemas/PersonResponse'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: PersonProjection
    FaceProjection:
      properties:
        kind:
          type: string
          const: face
          title: Kind
        key:
          $ref: '#/components/schemas/FaceProjectionKey'
          description: Stable key matching this projection value
        value:
          $ref: '#/components/schemas/FaceProjectionValue'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: FaceProjection
    StackProjection:
      properties:
        kind:
          type: string
          const: stack
          title: Kind
        key:
          $ref: '#/components/schemas/StackProjectionKey'
          description: Stable key matching this projection value
        value:
          $ref: '#/components/schemas/StackResponse'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: StackProjection
    AlbumProjection:
      properties:
        kind:
          type: string
          const: album
          title: Kind
        key:
          $ref: '#/components/schemas/AlbumProjectionKey'
          description: Stable key matching this projection value
        value:
          $ref: '#/components/schemas/AlbumResponse'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: AlbumProjection
    AlbumAssetProjection:
      properties:
        kind:
          type: string
          const: album_asset
          title: Kind
        key:
          $ref: '#/components/schemas/AlbumAssetProjectionKey'
          description: Stable album and asset pair key
        value:
          $ref: '#/components/schemas/AlbumAssetResponse'
          description: Fully materialized current domain value
      additionalProperties: false
      type: object
      required:
        - kind
        - key
        - value
      title: AlbumAssetProjection
    UserSummary:
      properties:
        id:
          type: string
          title: Id
          description: User identifier
        display_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Display Name
          description: Public display name, when available
      type: object
      required:
        - id
        - display_name
      title: UserSummary
    CurrentUserProjectionKey:
      properties:
        kind:
          type: string
          const: current_user
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: CurrentUserProjectionKey
    UserResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique user identifier with 'intuser_' prefix
        email:
          anyOf:
            - type: string
            - type: 'null'
          title: Email
          description: User's email address
        first_name:
          anyOf:
            - type: string
            - type: 'null'
          title: First Name
          description: User's first name
        last_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Last Name
          description: User's last name
        timezone:
          anyOf:
            - type: string
            - type: 'null'
          title: Timezone
          description: >-
            User's home timezone as an IANA zone id (e.g.
            'America/Los_Angeles'); null until a home zone is captured
        favorite_display_mode:
          $ref: '#/components/schemas/FavoriteDisplayMode'
          description: >-
            The user's effective favorite/rating display mode, defaulting to
            `favorite` when they have never selected one.
        demo_mode_enabled:
          type: boolean
          title: Demo Mode Enabled
          description: >-
            Whether demo-mode person-name presentation is enabled. Defaults to
            false.
        immich_library_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Immich Library Id
          description: >-
            The user's stored preferred library, or null to use the default.
            Reported as stored: the library may since have been trashed, or the
            user's access to it may have changed.
        home_country:
          anyOf:
            - type: string
            - type: 'null'
          title: Home Country
          description: >-
            The user's declared home country as an ISO 3166-1 alpha-2 code (e.g.
            'US'); null until declared
        home_subdivision:
          anyOf:
            - type: string
            - type: 'null'
          title: Home Subdivision
          description: >-
            The user's declared home state or province: an ISO 3166-2 code
            without its country prefix (e.g. 'CA' for US-CA); null when not
            declared
        face_detection_preference:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Face Detection Preference
          description: >-
            Whether automatic face detection is on for the libraries this user
            owns: true is on, false is off, null means the user has not chosen
            yet. Faces are currently detected automatically when this is true or
            null.
        face_detection_available:
          type: boolean
          title: Face Detection Available
          description: >-
            Whether automatic face detection can be turned on for this user.
            False when the declared home region is one where it is not offered;
            `face_detection_preference` is then false and cannot be set to true.
        is_active:
          type: boolean
          title: Is Active
          description: Whether this user account is currently active
        is_superuser:
          type: boolean
          title: Is Superuser
          description: Whether this user has superuser/admin privileges
        is_verified:
          type: boolean
          title: Is Verified
          description: >-
            Whether the account is marked verified. An internal account flag,
            not proof of email verification — it can be true even when `email`
            is null
        storage_used_bytes:
          type: integer
          title: Storage Used Bytes
          description: Total bytes of assets the user is currently storing
        storage_limit_bytes:
          type: integer
          title: Storage Limit Bytes
          description: Maximum bytes of assets the user may store
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this user account was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this user account was last updated
      type: object
      required:
        - id
        - favorite_display_mode
        - demo_mode_enabled
        - face_detection_preference
        - face_detection_available
        - is_active
        - is_superuser
        - is_verified
        - storage_used_bytes
        - storage_limit_bytes
        - created_at
        - updated_at
      title: UserResponse
      description: Represents a user account with profile information.
    AssetProjectionKey:
      properties:
        kind:
          type: string
          const: asset
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: AssetProjectionKey
    AssetResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique asset identifier with 'asset_' prefix
        mime_type:
          type: string
          title: Mime Type
          description: >-
            MIME type of the current rendering (e.g., 'image/jpeg',
            'video/mp4').
        original_file_name:
          type: string
          title: Original File Name
          description: Filename the asset was uploaded under.
        local_datetime:
          type: string
          format: date-time
          title: Local Datetime
          description: When the photo/video was taken, in the device's local timezone
        file_data:
          anyOf:
            - $ref: '#/components/schemas/FileDataResponse'
            - type: 'null'
          description: >-
            File/provenance scalars (device IDs, file timestamps, checksums,
            file size) grouped into one nested object. `null` when not requested
            via `include=file_data`; when present, every field is populated
            (`checksum_sha1` may still be `null` for legacy rows).
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this asset record was created in the database
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this asset record was last updated
        metadata:
          anyOf:
            - $ref: '#/components/schemas/MetadataResponse'
            - type: 'null'
          description: >-
            Asset metadata — camera/EXIF fields, GPS, and location names. `null`
            when not requested via `include=metadata`.
        asset_urls:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/AssetVariant'
              type: object
            - type: 'null'
          title: Asset Urls
          description: >-
            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:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: >-
            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).
        quality_score:
          anyOf:
            - type: number
              maximum: 1
              minimum: 0
            - type: 'null'
          title: Quality Score
          description: >-
            Photographic quality judged from the image alone (focus, exposure,
            noise, composition, capture flaws), from 0 (worst) to 1 (best) on a
            fixed scale that is comparable across photos and libraries. Scores
            take a few distinct values, so photos of similar quality tie. It
            does not reflect who is pictured. `null` means the asset has no
            score.
        thumbhash:
          anyOf:
            - type: string
            - type: 'null'
          title: Thumbhash
          description: >-
            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:
          anyOf:
            - items:
                $ref: '#/components/schemas/FaceResponse'
              type: array
            - type: 'null'
          title: Faces
          description: >-
            All faces detected in this asset. `null` when not requested via
            `include=faces`; `[]` when requested but the asset has no faces.
        people:
          anyOf:
            - items:
                $ref: '#/components/schemas/PersonResponse'
              type: array
            - type: 'null'
          title: People
          description: >-
            All unique people identified in this asset (deduplicated from
            faces). `null` when not requested via `include=people`; `[]` when
            requested but none are identified.
        kind:
          type: string
          title: Kind
          description: >-
            What produced the current rendering: `original` (the upload), `edit`
            (an edit rendered by the client), or `external:<service>`. The
            namespace is open — derive edited-ness as `kind != "original"`.
        current_version_id:
          type: string
          title: Current Version Id
          description: >-
            ID (`asset_version_` prefix) of the current version, which the
            top-level rendering fields describe. For a current derived version,
            this ID supplies the path target for replacement or deletion.
        width:
          type: integer
          title: Width
          description: Width of the current rendering in pixels.
          default: 0
        height:
          type: integer
          title: Height
          description: Height of the current rendering in pixels.
          default: 0
        file_size_bytes:
          type: integer
          title: File Size Bytes
          description: >-
            Size of the current rendering in bytes: the exact byte count the
            `asset_urls.original` download serves. For an unedited asset this
            equals the upload's `file_data.file_size_bytes`; for an edited asset
            it is the derived rendering's size.
        duration:
          anyOf:
            - type: number
            - type: 'null'
          title: Duration
          description: >-
            Video length in seconds. `null` for images and for videos whose
            duration has not been extracted yet.
        trashed_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Trashed At
          description: >-
            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:
          anyOf:
            - type: string
            - type: 'null'
          title: Stack Id
          description: >-
            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.
      type: object
      required:
        - id
        - mime_type
        - original_file_name
        - local_datetime
        - created_at
        - updated_at
        - kind
        - current_version_id
        - file_size_bytes
      title: AssetResponse
      description: |-
        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.
    PersonProjectionKey:
      properties:
        kind:
          type: string
          const: person
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: PersonProjectionKey
    PersonResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique person identifier with 'person_' prefix
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: >-
            Name assigned to this person, or null when unnamed. Names supplied
            as text on create or update are trimmed and must not be blank.
        birth_date:
          anyOf:
            - type: string
              format: date
            - type: 'null'
          title: Birth Date
          description: Optional birth date of this person
        is_hidden:
          type: boolean
          title: Is Hidden
          description: Whether this person should be hidden from the UI
        is_favorite:
          type: boolean
          title: Is Favorite
          description: Whether this person is marked as a favorite
        asset_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Asset Count
          description: >-
            Number of unique photos this person appears in, or null if not
            computed
        thumbnail_face_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Thumbnail Face Id
          description: ID of the face resource used as this person's thumbnail
        asset_urls:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/AssetVariant'
              type: object
            - type: 'null'
          title: Asset Urls
          description: >-
            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:
          anyOf:
            - $ref: '#/components/schemas/ClusterMetricsResponse'
            - type: 'null'
          description: >-
            Cohesion metrics for this person's face cluster. Populated only when
            `include=cluster_metrics` is requested on the people endpoint, and
            only for persons with a populated centroid (newly-created empty
            Persons will have null). See `ClusterMetricsResponse` for the shape.
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this person record was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this person record was last updated
      type: object
      required:
        - id
        - is_hidden
        - is_favorite
        - created_at
        - updated_at
      title: PersonResponse
      description: Represents a person identified through face clustering and recognition.
    FaceProjectionKey:
      properties:
        kind:
          type: string
          const: face
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: FaceProjectionKey
    FaceProjectionValue:
      properties:
        face:
          $ref: '#/components/schemas/FaceResponse'
          description: Eligible face in its original coordinate frame
        coordinate_width:
          type: integer
          title: Coordinate Width
          description: Original frame width in pixels
        coordinate_height:
          type: integer
          title: Coordinate Height
          description: Original frame height in pixels
      additionalProperties: false
      type: object
      required:
        - face
        - coordinate_width
        - coordinate_height
      title: FaceProjectionValue
    StackProjectionKey:
      properties:
        kind:
          type: string
          const: stack
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: StackProjectionKey
    StackResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique stack identifier with 'asset_stack_' prefix
        primary_asset_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Primary Asset Id
          description: >-
            ID of the asset the user pinned as the stack's cover, or null if
            none is pinned. Null for an auto-detected burst unless a user has
            since pinned a cover — there is no server-selected default, so a
            client showing a stack with no pinned cover picks its own. A pinned
            cover that has been trashed keeps its ID here; it is cleared only
            once the asset is permanently deleted.
        asset_count:
          type: integer
          title: Asset Count
          description: >-
            Number of live assets in this stack. Excludes trashed members, so it
            can drop below the number of frames originally grouped.
        origin:
          $ref: '#/components/schemas/StackOrigin'
        asset_ids:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          title: Asset Ids
          description: >-
            IDs of the stack's live members, earliest capture time first — the
            order `list_assets` returns for this `stack_id` with `order=asc`.
            Excludes trashed members, like `asset_count`. Only populated by
            `list_stacks` with `include=asset_ids`; null otherwise.
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this stack was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this stack was last updated
      type: object
      required:
        - id
        - asset_count
        - origin
        - created_at
        - updated_at
      title: StackResponse
      description: Represents a group of assets displayed as a single tile.
    AlbumProjectionKey:
      properties:
        kind:
          type: string
          const: album
          title: Kind
        id:
          type: string
          maxLength: 255
          minLength: 1
          title: Id
          description: >-
            Stable entity identifier; current_user must name the authenticated
            principal
      additionalProperties: false
      type: object
      required:
        - kind
        - id
      title: AlbumProjectionKey
    AlbumResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique album identifier with 'album_' prefix
        name:
          type: string
          title: Name
          description: >-
            Display name of the album. Names supplied as text on create or
            update are trimmed and must not be blank.
        description:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: Optional description text for the album
        asset_count:
          type: integer
          title: Asset Count
          description: Total number of assets in this album
        album_cover_asset_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Album Cover Asset Id
          description: >-
            ID of the asset displayed as the album cover. May be a
            server-selected default when the album has no explicit cover set, or
            null when the album has no live assets.
        asset_urls:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/AssetVariant'
              type: object
            - type: 'null'
          title: Asset Urls
          description: 'Asset variants for the album cover: ''thumbnail'''
        start_date:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Start Date
          description: >-
            The oldest asset date (local_datetime) in the album, or null if
            empty
        end_date:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: End Date
          description: >-
            The newest asset date (local_datetime) in the album, or null if
            empty
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this album was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this album was last updated
      type: object
      required:
        - id
        - name
        - asset_count
        - created_at
        - updated_at
      title: AlbumResponse
      description: Represents a collection of assets organized by the user.
    AlbumAssetResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique album_asset identifier with 'album_asset_' prefix
        album_id:
          type: string
          title: Album Id
          description: ID of the album
        asset_id:
          type: string
          title: Asset Id
          description: ID of the asset
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this link was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this link was last updated
      type: object
      required:
        - id
        - album_id
        - asset_id
        - created_at
        - updated_at
      title: AlbumAssetResponse
      description: Represents a link between an album and an asset.
    FavoriteDisplayMode:
      type: string
      enum:
        - favorite
        - rating
      title: FavoriteDisplayMode
      description: |-
        Presentation a user prefers for the favorite/rating control.

        - `favorite`: a heart — filled at the top rating, empty otherwise.
        - `rating`: a 0-5 star control.
    FileDataResponse:
      properties:
        device_asset_id:
          type: string
          title: Device Asset Id
          description: Original asset identifier from the device that uploaded this asset.
        device_id:
          type: string
          title: Device Id
          description: Identifier of the device that uploaded this asset.
        file_created_at:
          type: string
          format: date-time
          title: File Created At
          description: When the file was created on the uploading device.
        file_modified_at:
          type: string
          format: date-time
          title: File Modified At
          description: When the file was last modified on the uploading device.
        checksum:
          type: string
          title: Checksum
          description: >-
            Base64-encoded SHA-256 hash of the asset contents for duplicate
            detection and integrity.
        checksum_sha1:
          anyOf:
            - type: string
            - type: 'null'
          title: Checksum Sha1
          description: >-
            Base64-encoded SHA-1 hash of the asset contents. `null` for older
            assets that have no SHA-1.
        file_size_bytes:
          type: integer
          title: File Size Bytes
          description: >-
            Size of the uploaded file in bytes. The current rendering's size is
            the top-level `file_size_bytes`; the two differ once the asset is
            edited.
      type: object
      required:
        - device_asset_id
        - device_id
        - file_created_at
        - file_modified_at
        - checksum
        - file_size_bytes
      title: FileDataResponse
      description: >-
        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.
    MetadataResponse:
      properties:
        asset_id:
          type: string
          title: Asset Id
          description: ID of the asset this metadata belongs to
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this metadata record was created
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this metadata record was last updated
        make:
          anyOf:
            - type: string
            - type: 'null'
          title: Make
          description: Camera manufacturer (e.g., 'Canon', 'Nikon')
        model:
          anyOf:
            - type: string
            - type: 'null'
          title: Model
          description: Camera model (e.g., 'EOS 5D Mark IV')
        orientation:
          anyOf:
            - type: integer
            - type: 'null'
          title: Orientation
          description: >-
            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:
          anyOf:
            - type: integer
            - type: 'null'
          title: Raw Width
          description: >-
            Width in pixels of the original encoded image, before the EXIF
            `orientation` is applied. When both raw dimensions are positive,
            combine them with `orientation` to derive the original upload's
            display dimensions. Null or zero means unavailable; videos do not
            have raw dimensions.
        raw_height:
          anyOf:
            - type: integer
            - type: 'null'
          title: Raw Height
          description: >-
            Height in pixels of the original encoded image, before the EXIF
            `orientation` is applied. When both raw dimensions are positive,
            combine them with `orientation` to derive the original upload's
            display dimensions. Null or zero means unavailable; videos do not
            have raw dimensions.
        modified_datetime:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Modified Datetime
          description: When the file was last modified, with timezone offset if available
        original_datetime:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Original Datetime
          description: >-
            When the photo was originally taken, with timezone offset if
            available
        digitized_datetime:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Digitized Datetime
          description: When the photo was digitized, with timezone offset if available
        lens_model:
          anyOf:
            - type: string
            - type: 'null'
          title: Lens Model
          description: Lens model used (e.g., 'EF 24-70mm f/2.8L II USM')
        f_number:
          anyOf:
            - type: number
            - type: 'null'
          title: F Number
          description: Aperture f-stop value (e.g., 2.8, 5.6)
        focal_length:
          anyOf:
            - type: number
            - type: 'null'
          title: Focal Length
          description: Focal length in millimeters
        iso:
          anyOf:
            - type: integer
            - type: 'null'
          title: Iso
          description: ISO sensitivity value (e.g., 100, 800, 3200)
        exposure_time:
          anyOf:
            - type: number
            - type: 'null'
          title: Exposure Time
          description: Shutter speed in seconds (e.g., 0.001 for 1/1000s)
        exposure_bias:
          anyOf:
            - type: number
            - type: 'null'
          title: Exposure Bias
          description: Exposure compensation in EV (e.g., -1.0, +0.5)
        latitude:
          anyOf:
            - type: number
            - type: 'null'
          title: Latitude
          description: GPS latitude in decimal degrees
        longitude:
          anyOf:
            - type: number
            - type: 'null'
          title: Longitude
          description: GPS longitude in decimal degrees
        altitude:
          anyOf:
            - type: number
            - type: 'null'
          title: Altitude
          description: GPS altitude in meters
        city:
          anyOf:
            - type: string
            - type: 'null'
          title: City
          description: City name
        state:
          anyOf:
            - type: string
            - type: 'null'
          title: State
          description: State/province name
        country:
          anyOf:
            - type: string
            - type: 'null'
          title: Country
          description: Country name
        country_code:
          anyOf:
            - type: string
            - type: 'null'
          title: Country Code
          description: ISO 3166-1 alpha-2 country code (e.g., 'US', 'JP')
        sublocation:
          anyOf:
            - type: string
            - type: 'null'
          title: Sublocation
          description: Neighborhood or district
        place_name:
          anyOf:
            - type: string
            - type: 'null'
          title: Place Name
          description: Landmark or point-of-interest name
        timezone:
          anyOf:
            - type: string
            - type: 'null'
          title: Timezone
          description: IANA timezone identifier (e.g., 'America/Los_Angeles')
        display_label:
          anyOf:
            - type: string
            - type: 'null'
          title: Display Label
          description: >-
            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:
          anyOf:
            - type: string
            - type: 'null'
          title: Description
          description: Image description or caption
        fps:
          anyOf:
            - type: number
            - type: 'null'
          title: Fps
          description: Frame rate for video files
        live_photo_cid:
          anyOf:
            - type: string
            - type: 'null'
          title: Live Photo Cid
          description: Live photo content identifier
        projection_type:
          anyOf:
            - type: string
            - type: 'null'
          title: Projection Type
          description: Projection type (e.g., for 360° photos)
        auto_stack_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Auto Stack Id
          description: Identifier for automatic photo stacking
        rating:
          anyOf:
            - type: integer
            - type: 'null'
          title: Rating
          description: >-
            Effective user-or-camera rating from `0` to `5` stars. `0` means
            unrated; values outside this range are normalized to `0`.
      type: object
      required:
        - asset_id
        - created_at
        - updated_at
      title: MetadataResponse
      description: Metadata for an asset — camera/EXIF fields, GPS, and location names.
    AssetVariant:
      properties:
        url:
          type: string
          title: Url
          description: URL to fetch this image variant
        mimetype:
          type: string
          title: Mimetype
          description: MIME type of the served image
        width:
          anyOf:
            - type: integer
            - type: 'null'
          title: Width
          description: Target width in pixels (null if unknown)
      type: object
      required:
        - url
        - mimetype
      title: AssetVariant
      description: A single image variant with its URL, MIME type, and target width.
    FaceResponse:
      properties:
        id:
          type: string
          title: Id
          description: Unique face identifier with 'face_' prefix
        asset_id:
          type: string
          title: Asset Id
          description: ID of the asset containing this face
        person_id:
          anyOf:
            - type: string
            - type: 'null'
          title: Person Id
          description: ID of the person this face belongs to (if identified)
        bounding_box:
          additionalProperties:
            type: integer
          type: object
          title: Bounding Box
          description: Face location as {x, y, w, h} coordinates in pixels
        confidence:
          anyOf:
            - type: number
            - type: 'null'
          title: Confidence
          description: >-
            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:
          type: string
          enum:
            - automatic
            - manual
          title: Source
          description: >-
            How this face was added: 'automatic' for detector-found faces,
            'manual' for user-drawn face boxes.
        timestamp_ms:
          anyOf:
            - type: integer
            - type: 'null'
          title: Timestamp Ms
          description: For video files, timestamp in milliseconds when face appears
        asset_urls:
          anyOf:
            - additionalProperties:
                $ref: '#/components/schemas/AssetVariant'
              type: object
            - type: 'null'
          title: Asset Urls
          description: 'Asset variants for this face: ''thumbnail'' with face crop'
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When this face was detected and recorded
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When this face record was last updated
        cluster_assignment:
          anyOf:
            - $ref: '#/components/schemas/ClusterAssignmentResponse'
            - type: 'null'
          description: >-
            Cluster-assignment diagnostics for this face. Populated only when
            `include=cluster_assignment` is requested on the faces endpoint;
            null otherwise. See `ClusterAssignmentResponse` for the shape.
      type: object
      required:
        - id
        - asset_id
        - bounding_box
        - source
        - created_at
        - updated_at
      title: FaceResponse
      description: Represents a detected face in an asset with facial recognition data.
    ClusterMetricsResponse:
      properties:
        pairwise_p90:
          type: number
          title: Pairwise P90
          description: >-
            90th-percentile pairwise cosine distance between faces in this
            person's cluster. Lower = more cohesive cluster.
        pairwise_mean:
          type: number
          title: Pairwise Mean
          description: >-
            Mean pairwise cosine distance between faces in this person's
            cluster.
        face_count:
          type: integer
          title: Face Count
          description: >-
            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).
      type: object
      required:
        - pairwise_p90
        - pairwise_mean
        - face_count
      title: ClusterMetricsResponse
      description: |-
        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).
    StackOrigin:
      type: string
      enum:
        - auto_burst
        - user
      title: StackOrigin
      description: >-
        How a stack came to exist.


        `auto_burst` marks a stack the burst detector created from the time +

        EXIF-camera signal; `user` marks a stack a user created or edited
        (manual

        create, set-cover, add/remove, unstack). The distinction is what keeps

        re-detection from stomping a user's correction — the detection pass
        skips

        `user` stacks.
    ClusterAssignmentResponse:
      properties:
        distance_to_person:
          anyOf:
            - type: number
            - type: 'null'
          title: Distance To Person
          description: >-
            Cosine distance from the face's embedding to its currently-assigned
            Person's centroid. Lower = better fit. Null when the face is
            unassigned, when the assigned Person has no centroid, or when the
            library owner's settings do not allow automatic face detection.
        candidates:
          items:
            $ref: '#/components/schemas/FaceCandidatePersonResponse'
          type: array
          title: Candidates
          description: >-
            Eligible nearby Persons in the same library, sorted ascending by
            distance. Excludes the face's currently-assigned Person (its
            distance is in `distance_to_person`) and people marked hidden
            (`is_hidden`). Empty when there are no eligible nearby Persons, or
            when the library owner's settings do not allow automatic face
            detection.
      type: object
      title: ClusterAssignmentResponse
      description: |-
        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.
    FaceCandidatePersonResponse:
      properties:
        person_id:
          type: string
          title: Person Id
          description: Person ID (with 'person_' prefix) of the candidate.
        name:
          anyOf:
            - type: string
            - type: 'null'
          title: Name
          description: Display name of the candidate Person, or null for an unnamed Person.
        distance:
          type: number
          title: Distance
          description: >-
            Cosine distance from the face's embedding to this Person's centroid
            (lower = closer).
      type: object
      required:
        - person_id
        - distance
      title: FaceCandidatePersonResponse
      description: A nearby Person returned under `ClusterAssignmentResponse.candidates`.
  securitySchemes:
    apiKeyAuth:
      type: http
      scheme: bearer
      description: >-
        Gumnut API key (`apikey_...`) sent as a Bearer token in the
        `Authorization` header. Create and manage keys in the Gumnut app, or
        with the API key endpoints while signed in to it.
    oauthJwtAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        Short-lived JWT obtained from the OAuth token exchange, sent as a Bearer
        token in the `Authorization` header.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.