GET /v1/projects/:projectId/content
List content containers on a project, filtered by status, format, and time range.
GET
/v1/projects/:projectId/contentPhase 1stable
- Auth
- Bearer
- Scope
- content:read
Cursor-paginated list of containers, newest first. Filter by generation status, format, or a time window.
Path parameters
projectIdstring (uuid)requiredProject to list containers for.
Query parameters
statusstring | string[]optionalFilter on generation status. Repeat the param to combine.One of:queued,processing,completed,failed,canceledformatstring | string[]optionalFilter 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.One of:slideshow-builder,ugc-remix,video-remix,slideshow-remixcreativeTypestringoptionalFilter on origin: generated content vs. uploaded content. Omit for a mixed list — every item carries its own `creativeType`.One of:generated,uploadedsincestring (ISO 8601, UTC Z)optionalOnly containers created at or after this timestamp.untilstring (ISO 8601, UTC Z)optionalOnly containers created at or before this timestamp.cursorstringoptionalOpaque 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).limitintegeroptionaldefault: 25Max 200.
Request
curl "https://api.layers.com/v1/projects/{projectId}/content?status=completed&limit=20" \
-H "Authorization: Bearer $LAYERS_API_KEY"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();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()Responses
200Page of containers.
{
"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"
}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 freshhook. - 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'spreview.imageUrls. - Uploads-only.
creativeType=uploaded&status=completed- the library of finished content you uploaded, ready to schedule. List rows carrycreativeTypeandadsEnrollment; the full per-platformplatformFitlives onGET /v1/content/:id.
Each list row carries the canonical Preview object so a gallery view can render directly off the list response.
Errors
| Code | When |
|---|---|
VALIDATION | Bad enum value, limit > 200. |
NOT_FOUND | Project id not in this org. |