---
title: "List stacks in a library"
method: GET
path: "/api/stacks"
tags: ["stacks"]
---

# List stacks in a library

`GET /api/stacks`

Returns a paginated list of stacks — assets grouped for collapsed display, whether detected automatically or grouped by the user — ordered by `id`: stable, but arbitrary rather than chronological.

`list_stacks` returns stack metadata only; it does not return the assets inside a stack. To get a stack's frames, use `list_assets` with `stack_id`.

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

## Query parameters

- `library_id` string, nullable — Library to list stacks from. Optional if the user has a single live (non-trashed) library; required when they have multiple.
- `origin` 'auto_burst' | 'user' — 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.
- `primary_asset_id` string, nullable — Return only the stack that pins this asset (with `asset_` prefix) as its cover.
- `ids` string[], nullable — Look up specific stacks by ID (max 200; each ID has the `asset_stack_` prefix). Accepts multiple `ids=` query params or a single comma-delimited value (e.g., `ids=asset_stack_1,asset_stack_2`).
- `limit` integer — Maximum number of stacks to return per page (1–200). Defaults to 20.
- `starting_after_id` string, nullable — Cursor for pagination. Pass the `id` of the last stack in the previous response's `data` to fetch the next page. Omit for the first page.

## Response `200`

Successful Response

- PaginatedStacksResponse
  - `data` StackResponse[], required — List of stacks
    - `id` string, required — Unique stack identifier with 'asset_stack_' prefix
    - `primary_asset_id` string, nullable — 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` integer, required — Number of live assets in this stack. Excludes trashed members, so it can drop below the number of frames originally grouped.
    - `origin` 'auto_burst' | 'user', required — 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.
    - `created_at` string, date-time, required — When this stack was created
    - `updated_at` string, date-time, required — When this stack was last updated
  - `has_more` boolean, required — True if there are more stacks after this page. Pass the last stack'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)
