Content items
Containers are the unit of generated content. Each container holds media, captions, and scheduling metadata for one creative.
A content item — or, to use the field name, a content container — is one generated creative. It holds the rendered media, the captions, the hook, the format, the influencer that voiced it, and the approval state. When we talk about "a piece of content" in this API, we mean a container.
Generation is async. You POST a brief, you get back a job envelope with a jobId and a containerId, and you poll either the job envelope for progress or the container for the final shape.
Lifecycle
Container status values (from the ContainerStatus enum):
queued— job accepted, not yet running.generating— generation job is running. Media assets are empty until complete.completed— generation finished. Media and captions are populated. If the project's approval policy requires review, the container'sapprovalStatuswill bepending.failed— generation failed. ChecklastErroron the container.canceled— container was canceled (by explicit cancel or project archive).
Approval status is independent of container status — it lives on approvalStatus and takes values not_required, pending, approved, or rejected.
Creating one
POST /v1/projects/:projectId/content
Content-Type: application/json
X-Api-Key: $LAYERS_API_KEY
Idempotency-Key: 7c2f1a3e-0b4c-4a11-9f7e-33c0a2c1bd55
{
"format": "auto",
"brief": {
"hook": "The calendar app that finally respects your evenings",
"targetPlatforms": ["tiktok", "instagram"],
"influencerId": "inf_01HX9Y6K7EJ4T2ABCDEF",
"themeTags": ["launch"],
"referenceMediaIds": ["med_01HX9Y6K7EJ4T2ABCDEF"],
"language": "en-US"
}
}
→ 202
{
"jobId": "job_01HX9Y6K7EJ4T2ABCDEF01234",
"kind": "content_generate",
"status": "running",
"stage": "queued",
"projectId": "254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
"containerId": "cnt_01HX9Y6K7EJ4T2ABCDEF",
"locationUrl": "/v1/jobs/job_01HX9Y6K7EJ4T2ABCDEF01234",
"startedAt": "2026-04-18T12:04:11.000Z"
}Pair Idempotency-Key with every generate call. A retry inside the 24-hour window replays the original 202; a conflicting body returns 409 IDEMPOTENCY_CONFLICT rather than billing you for a duplicate job.
Formats
format | When to use |
|---|---|
video_remix | Edited video cut from your reference media + generated overlays. |
slideshow_remix | Multi-image slideshow with typographic hooks. |
ugc_remix | UGC-style influencer video, voiced by the selected persona. |
auto | Server picks based on reference media and brand signals. The safest default. |
Reading a container
GET /v1/content/:containerId
→ 200
{
"id": "cnt_01HX9Y6K7EJ4T2ABCDEF",
"projectId": "254a4ce1-f4ca-42b1-9e36-17ca45ef3d39",
"status": "completed",
"approvalStatus": "approved",
"format": "video_remix",
"influencerId": "inf_01HX9Y6K7EJ4T2ABCDEF",
"brief": { "hook": "The calendar app that finally...", "targetPlatforms": ["tiktok"] },
"assets": [
{
"id": "med_01HX9Y6K7EJ4T2ABCDEF",
"kind": "video",
"url": "https://media.layers.com/...",
"width": 1080,
"height": 1920,
"durationMs": 27500
}
],
"captions": [
{ "platform": "tiktok", "text": "..." }
],
"lastError": null,
"createdAt": "2026-04-18T12:04:11.000Z",
"updatedAt": "2026-04-18T12:07:33.000Z"
}Media URLs on assets[].url are long-lived permanent URLs. If you need a short-lived signed URL (your infra wants to re-host), use GET /v1/content/:id/assets/:assetId.
Regenerating, cloning, rejecting
POST /v1/content/:id/regenerate— remix the same container. Takes an optionalpatchthat overrides brief fields. Returns202with a newjobId; the container id is preserved. Good for "same brief, different render."POST /v1/content/:id/clone-from-post— fork or reimagine an existing platform post (yours or a top performer). Produces a new container with a new id.POST /v1/content/:id/reject— reject through the approval gate. Optionally kicks off a regeneration atomically.
Listing
GET /v1/projects/:projectId/content?status=completed&format=video_remix&limit=25Filters: status, format, cursor, limit. Cursor-paginated. Pass status=completed when you're rendering a library view; combine with an approval query to drive your review UX.
Progress during generation
For an in-flight container, both endpoints tell you the same story from different angles:
GET /v1/jobs/:jobId— canonical progress. Use this by default.GET /v1/content/:id/progress— same shape, scoped to the container. Useful if you've lost thejobId.