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

# Move assets to another library

> Moves the given assets from one library to another, keeping their IDs and stored files. The caller must own the source library and either own the destination library or be a collaborator on it. A scoped credential must cover both libraries and allow both `delete_permanently` and `write`. Moved assets leave the source library's albums, people, and stacks.

Returns 200 with one result per asset even when some assets could not be moved. Each result describes the asset's state when the request ran, so repeating a request is safe: an asset already in the destination library is reported as a success.

Returns 409 when a concurrent change interrupted the request; nothing was moved, so retry it unchanged. Returns 503 while moving assets is turned off; retry later.



## OpenAPI

````yaml https://api.gumnut.ai/openapi.json post /api/assets/move
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: 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: server
    description: Service health.
paths:
  /api/assets/move:
    post:
      tags:
        - assets
      summary: Move assets to another library
      description: >-
        Moves the given assets from one library to another, keeping their IDs
        and stored files. The caller must own the source library and either own
        the destination library or be a collaborator on it. A scoped credential
        must cover both libraries and allow both `delete_permanently` and
        `write`. Moved assets leave the source library's albums, people, and
        stacks.


        Returns 200 with one result per asset even when some assets could not be
        moved. Each result describes the asset's state when the request ran, so
        repeating a request is safe: an asset already in the destination library
        is reported as a success.


        Returns 409 when a concurrent change interrupted the request; nothing
        was moved, so retry it unchanged. Returns 503 while moving assets is
        turned off; retry later.
      operationId: move_assets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MoveAssetsRequest'
        required: true
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MoveAssetsResponse'
        '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: >-
            A concurrent change interrupted the request and nothing was moved.
            Retry the request unchanged. 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:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UnprocessableEntityResponse'
        '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: >-
            Moving assets is turned off; retry later. Authentication provider
            outages also return 503; retry sign-in later.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    MoveAssetsRequest:
      properties:
        source_library_id:
          type: string
          title: Source Library Id
          description: Library the assets are in now. The caller must own it.
        destination_library_id:
          type: string
          title: Destination Library Id
          description: >-
            Library to move the assets into. The caller must own it or be a
            collaborator on it. Must differ from `source_library_id`.
        asset_ids:
          items:
            type: string
          type: array
          maxItems: 200
          minItems: 1
          title: Asset Ids
          description: Asset IDs (each with the `asset_` prefix) to move.
      type: object
      required:
        - source_library_id
        - destination_library_id
        - asset_ids
      title: MoveAssetsRequest
      description: Request body for moving assets from one library to another.
    MoveAssetsResponse:
      properties:
        data:
          items:
            $ref: '#/components/schemas/AssetMoveResult'
          type: array
          title: Data
          description: One result per distinct requested asset ID, in request order.
      type: object
      required:
        - data
      title: MoveAssetsResponse
    ErrorResponse:
      title: ErrorResponse
      type: object
      properties:
        detail:
          title: Detail
          type: string
          description: Human-readable explanation of the error.
      required:
        - detail
    UnprocessableEntityResponse:
      title: UnprocessableEntityResponse
      type: object
      properties:
        detail:
          title: Detail
          description: >-
            A semantic validation message or structured request-validation
            errors.
          oneOf:
            - type: string
              description: Human-readable semantic validation message.
            - type: array
              items:
                $ref: '#/components/schemas/ValidationError'
              description: Structured request-validation errors.
      required:
        - detail
    AssetMoveResult:
      properties:
        asset_id:
          type: string
          title: Asset Id
          description: Requested asset ID.
        outcome:
          $ref: '#/components/schemas/AssetMoveOutcome'
        failure:
          anyOf:
            - $ref: '#/components/schemas/AssetMoveFailure'
            - type: 'null'
          description: Set only when `outcome` is `failed`.
      type: object
      required:
        - asset_id
        - outcome
      title: AssetMoveResult
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    AssetMoveOutcome:
      type: string
      enum:
        - moved
        - already_in_destination
        - failed
      title: AssetMoveOutcome
      description: |-
        What a move request did with one asset.

        - `moved`: the asset is now in the destination library.
        - `already_in_destination`: the asset was already in the destination
          library, so nothing changed. This is a success.
        - `failed`: the asset was not moved; `failure` says why.
    AssetMoveFailure:
      type: string
      enum:
        - unavailable
        - changed_source
        - duplicate
        - quota
        - busy
      title: AssetMoveFailure
      description: |-
        Why an asset was not moved.

        - `unavailable`: the asset does not exist, is in the trash, or is not
          accessible.
        - `changed_source`: the asset is no longer in the source library.
        - `duplicate`: the destination library already holds an asset with the
          same original file, possibly in its trash.
        - `quota`: the destination library has no storage room for the asset.
        - `busy`: another operation is changing the asset. Retry the request.
  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.