# POST /v1/projects/:projectId/content/slideshow-builder (/docs/api/reference/content/slideshow-builder)



<Endpoint method="POST" path="/v1/projects/:projectId/content/slideshow-builder" scope="content:write" phase="1">
  Starts a content-generate [job](/docs/api/concepts/jobs). Returns `202`
  with `containerIds` (single-element array — the partner surface never
  fans out variants), a `jobId`, and a `locationUrl`.
</Endpoint>

The format is the URL — there is no `format` discriminator in the body. The only required input is `hook`. `socialAccountId` and `influencerId` are optional axes that resolve voice / language / influencer when supplied.

`slideshow-builder` is the only format that allows a layerless run with neither `socialAccountId` nor `influencerId` — the workflow falls back to the project's default voice and language. Every other format requires a named on-camera actor.

## Path parameters [#path-parameters]

<Parameters
  rows="[
  { name: 'projectId', type: 'string (uuid)', required: true, description: 'The project to generate content for.' },
]"
/>

## Body [#body]

<Parameters
  title="Body"
  rows="[
  { name: 'hook', type: 'string', required: true, description: 'Used verbatim as the slideshow first-slide overlay. 1–2000 chars; line breaks and emoji preserved. Pull from `/content/hooks` or send your own.' },
  { name: 'socialAccountId', type: 'string', description: 'Connected social-account id. Walks the wiring chain to anchor the container on the wired content layer and use that layer\'s influencer voice/language.' },
  { name: 'influencerId', type: 'string', description: 'Explicit influencer override. Wins over the wired influencer when both are supplied. Required for partners with no connected social account who want a non-default voice.' },
]"
/>

## Resolution rules [#resolution-rules]

| `socialAccountId` | `influencerId` | Behavior                                                                                          |
| ----------------- | -------------- | ------------------------------------------------------------------------------------------------- |
| Provided          | —              | Walk chain. Use wired influencer's voice/language. Container anchored to the wired content layer. |
| —                 | Provided       | Use that influencer directly. Layerless container (unassigned pool).                              |
| Provided          | Provided       | Walk chain for layer anchoring; use the override for voice/language.                              |
| —                 | —              | Project default voice/language. Layerless container.                                              |

## Request [#request]

<Tabs items="['curl', 'TypeScript', 'Python']">
  <Tab value="curl">
    ```sh title="terminal"
    curl -X POST https://api.layers.com/v1/projects/{projectId}/content/slideshow-builder \
      -H "Authorization: Bearer $LAYERS_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "hook": "wait for it...\nthis simple habit changed everything 🧠"
      }'
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts title="slideshow-builder.ts"
    const res = await fetch(
      `https://api.layers.com/v1/projects/${projectId}/content/slideshow-builder`,
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${process.env.LAYERS_API_KEY}`,
          'Content-Type': 'application/json',
          'Idempotency-Key': crypto.randomUUID(),
        },
        body: JSON.stringify({
          hook: 'wait for it...\nthis simple habit changed everything 🧠',
          influencerId: 'inf_4a8e1bc2...',
        }),
      },
    );
    const { jobId, containerIds } = await res.json();
    const [containerId] = containerIds;
    ```
  </Tab>

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

    r = httpx.post(
        f"https://api.layers.com/v1/projects/{project_id}/content/slideshow-builder",
        headers={
            "Authorization": f"Bearer {os.environ['LAYERS_API_KEY']}",
            "Idempotency-Key": str(uuid.uuid4()),
        },
        json={"hook": "wait for it...\nthis simple habit changed everything 🧠"},
    )
    job = r.json()
    ```
  </Tab>
</Tabs>

## Responses [#responses]

<Response status="202" description="Job accepted. The container exists in `processing` status — poll the job and the container.">
  ```json
  {
    "jobId": "job_01HZX3...",
    "kind": "content_generate",
    "status": "running",
    "containerIds": ["cnt_7d18b9a1..."],
    "locationUrl": "/v1/jobs/job_01HZX3..."
  }
  ```
</Response>

<Response status="422" description="Resolution failure or precondition not met.">
  ```json
  {
    "error": {
      "code": "VALIDATION",
      "message": "MISSING_APP_DESCRIPTION: slideshow-builder requires projects.app_description.",
      "requestId": "req_...",
      "details": {
        "code": "MISSING_APP_DESCRIPTION",
        "format": "slideshow-builder"
      }
    }
  }
  ```

  The top-level `error.code` is the generic `VALIDATION` envelope. The specific failure code lives at `error.details.code` — that's what partners switch on programmatically.

  | `details.code`            | Cause                                                                            |
  | ------------------------- | -------------------------------------------------------------------------------- |
  | `MISSING_APP_DESCRIPTION` | `projects.app_description` empty. Run an ingest job or `PATCH /v1/projects/:id`. |
  | `ACCOUNT_NOT_WIRED`       | `socialAccountId` exists but no distribution layer references it.                |
  | `NO_CONTENT_LAYER_WIRED`  | Distribution layer's `contentLayerSourceIds[]` is empty.                         |
  | `INFLUENCER_NOT_WIRED`    | Wired content layer has no `customInfluencerId`.                                 |
</Response>

<Response status="404" description="`socialAccountId` or `influencerId` not on this project.">
  ```json
  {
    "error": {
      "code": "NOT_FOUND",
      "message": "socialAccountId is not on this project.",
      "requestId": "req_..."
    }
  }
  ```
</Response>

## Errors [#errors]

| Code                                                                    | When                                                    |
| ----------------------------------------------------------------------- | ------------------------------------------------------- |
| `VALIDATION`                                                            | Missing `hook`, body shape invalid, body `id` set.      |
| `NOT_FOUND`                                                             | `socialAccountId` / `influencerId` not on this project. |
| `MISSING_APP_DESCRIPTION`                                               | Project missing `app_description`.                      |
| `ACCOUNT_NOT_WIRED` / `NO_CONTENT_LAYER_WIRED` / `INFLUENCER_NOT_WIRED` | `socialAccountId` resolution failed mid-chain.          |
| `IDEMPOTENCY_CONFLICT`                                                  | Same `Idempotency-Key` reused with different body.      |
| `BILLING_EXHAUSTED`                                                     | Org wallet at zero.                                     |

## See also [#see-also]

* [Hooks bank](/docs/api/reference/content/list-hooks)
* [The jobs envelope](/docs/api/concepts/jobs)
* [Approve generated content](/docs/api/reference/approval/approve-content)
