---
title: "Cast the narrator for this cut."
method: POST
path: "/trailers/{jobId}/narrator"
tags: ["Trailer"]
---

# Cast the narrator for this cut.

`POST /trailers/{jobId}/narrator`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/trailers/{jobId}/narrator`
- Auth: HTTP bearer

Choose the voice that narrates this trailer, or send `voiceId: null` to clear it (the cut then narrates in the cast canon's NARRATOR when the canon casts one). The narrator belongs to the TRAILER: it need not be a cast member and need not match the table read's narrator. Storing the choice costs nothing — the voice is spoken at render — and re-casting is cheap, because narration is a separate track mixed over the finished cut, so a change re-renders audio and never a frame. Requires `Idempotency-Key`. Scope: `story:write`.

## Headers

- `Idempotency-Key` string, required

## Request body

- object
  - `voiceId` string, nullable, required: Studio voice id, or null to clear the narrator.
  - `provider` 'cartesia' | 'elevenlabs' | 'openai' | 'deepgram' | 'hume' | 'null', nullable: The voice's provider. Inferred when omitted.

## Response `200`

The cast narrator.

- object
  - `narrator` TrailerNarrator, required: The voice a trailer's narrated beats are spoken in: the voice cast for this cut, else the cast canon's NARRATOR. Show `voiceName`, never the id.
    - `voiceId` string, nullable, required: The voice every narrated beat is spoken in; null when neither the cut nor the canon casts one (correct for a `suppress` cut, blocking for a `narrate` one).
    - `voiceName` string, nullable, required: The voice's name, as the writer is shown it; null when nothing names it. Show this, never the id.
    - `provider` string, nullable, required: Its TTS provider.
    - `source` 'override' | 'cast_canon' | 'null', nullable, required: Where it comes from: `override` (cast for this cut) or `cast_canon` (the canon's NARRATOR); null when there is none.
    - `overridden` boolean, required: True when this cut casts its own narrator.
    - `audioPolicy` string, required: The cut's audio policy: `narrate` speaks each beat's narration in this voice; `suppress` lets the on-screen text carry it.

## Other responses

- `400`: Request payload failed validation. The error message names the offending field.
- `401`: Missing, malformed, revoked, or expired API key.
- `403`: API key is valid but lacks the scope, is blocked by IP allowlist, or the account is disabled.
- `404`: The named project or source does not exist or is owned by another account.
- `429`: Rate limit for this API key + IP + route family was exceeded.
- `500`: The API failed unexpectedly. Safe to retry with the same Idempotency-Key.

---

[API](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api.md) · [All operations](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/llms.txt) · [OpenAPI document](https://skmtc.dev/sleeperhit/apis/sleeper-hit-studio-story-api/revisions/4534f5d25540?raw)
