# GET /v1/projects/:projectId/content (/docs/api/reference/content/list-containers)



<Endpoint method="GET" path="/v1/projects/:projectId/content" scope="content:read" phase="1" />

Cursor-paginated list of containers, newest first. Filter by generation status, format, or a time window.

## Path parameters [#path-parameters]

<Parameters
  rows="[
  { name: 'projectId', type: 'string (uuid)', required: true, description: 'Project to list containers for.' },
]"
/>

## Query parameters [#query-parameters]

<Parameters
  rows="[
  { name: 'status', type: 'string | string[]', description: 'Filter on generation status. Repeat the param to combine.', enum: ['queued', 'processing', 'completed', 'failed', 'canceled'] },
  { name: 'format', type: 'string | string[]', description: 'Filter on format. Reserved formats `video-remix` and `slideshow-remix` are not yet partner-callable on POST but may appear on GET for legacy/internal-generated rows.', enum: ['slideshow-builder', 'ugc-remix', 'video-remix', 'slideshow-remix'] },
  { name: 'creativeType', type: 'string', description: 'Filter on origin: generated content vs. uploaded content. Omit for a mixed list — every item carries its own `creativeType`.', enum: ['generated', 'uploaded'] },
  { name: 'since', type: 'string (ISO 8601, UTC Z)', description: 'Only containers created at or after this timestamp.' },
  { name: 'until', type: 'string (ISO 8601, UTC Z)', description: 'Only containers created at or before this timestamp.' },
  { name: 'cursor', type: 'string', description: 'Opaque cursor from the previous page. Pass the `nextCursor` value verbatim - do not decode or modify it. Cursors are bound to the original sort (created_at desc).' },
  { name: 'limit', type: 'integer', default: '25', description: 'Max 200.' },
]"
/>

## Request [#request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```sh title="terminal"
    curl "https://api.layers.com/v1/projects/{projectId}/content?status=completed&limit=20" \
      -H "Authorization: Bearer $LAYERS_API_KEY"
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts title="list-containers.ts"
    const params = new URLSearchParams({
      status: 'completed',
      limit: '50',
    });
    const res = await fetch(
      `https://api.layers.com/v1/projects/${projectId}/content?${params}`,
      { headers: { 'Authorization': `Bearer ${process.env.LAYERS_API_KEY}` } },
    );
    const { items, nextCursor } = await res.json();
    ```
  </Tab>

  <Tab value="Python">
    ```py title="list_containers.py"
    import os, httpx

    r = httpx.get(
        f"https://api.layers.com/v1/projects/{project_id}/content",
        params={"status": ["completed", "failed"], "format": ["slideshow-builder"]},
        headers={"Authorization": f"Bearer {os.environ[\'LAYERS_API_KEY\']}"},
    )
    data = r.json()
    ```
  </Tab>
</Tabs>

## Responses [#responses]

<Response status="200" description="Page of containers.">
  ```json
  {
    "items": [
      {
        "id": "cnt_7d18b9a1...",
        "status": "completed",
        "format": "slideshow-builder",
        "caption": "Your first 30 days of running.",
        "creativeType": "generated",
        "adsEnrollment": "auto",
        "approvalStatus": "pending",
        "createdAt": "2026-04-17T13:10:00Z",
        "completedAt": "2026-04-17T13:14:22Z",
        "preview": {
          "kind": "slideshow",
          "primaryUrl": "https://media.layers.com/.../slide-01.jpg",
          "thumbnailUrl": "https://media.layers.com/.../slide-01.jpg",
          "imageUrls": [
            "https://media.layers.com/.../slide-01.jpg",
            "https://media.layers.com/.../slide-02.jpg",
            "https://media.layers.com/.../slide-03.jpg"
          ],
          "aspectRatio": "9:16"
        },
        "primaryAsset": {
          "assetId": "ast_01HXZ9...",
          "kind": "image",
          "thumbnailUrl": "https://media.layers.com/.../slide-01.jpg"
        }
      }
    ],
    "nextCursor": "eyJjcmVhdGVkQXQiOiIyMDI2LTA0LTE3VDEzOjEwOjAwWiIsImlkIjoiNzg5NGIxZDUtMmFhNy00MWY5LWE4NTktMjgwMzA2ZWE1NjcyIn0"
  }
  ```
</Response>

## Common filters [#common-filters]

* **Rescue failed jobs.** `status=failed&since=2026-04-01T00:00:00Z` - sweep for broken containers to retry by calling generate again with a fresh `hook`.
* **In-flight work.** `status=queued&status=processing` - everything currently being produced.
* **UGC-only.** `format=ugc-remix` - if you're running a separate UGC review flow from brand content.
* **Slideshow-only.** `format=slideshow-builder` - render image grids using each row's `preview.imageUrls`.
* **Uploads-only.** `creativeType=uploaded&status=completed` - the library of finished content you uploaded, ready to schedule. List rows carry `creativeType` and `adsEnrollment`; the full per-platform `platformFit` lives on [`GET /v1/content/:id`](/docs/api/reference/content/get-container).

Each list row carries the canonical [Preview object](/docs/api/concepts/preview-object) so a gallery view can render directly off the list response.

## Errors [#errors]

| Code         | When                           |
| ------------ | ------------------------------ |
| `VALIDATION` | Bad enum value, `limit > 200`. |
| `NOT_FOUND`  | Project id not in this org.    |

## See also [#see-also]

* [Read one container](/docs/api/reference/content/get-container)
* [Approve pending containers](/docs/api/reference/approval/approve-content)
* [Generate a new container](/docs/api/reference/content/slideshow-builder)
