---
title: "Design a cast member's voice from a description (metered — TWO CALLS, price first)."
method: POST
path: "/story-projects/{projectId}/cast-voice/design"
tags: ["Projects"]
---

# Design a cast member's voice from a description (metered — TWO CALLS, price first).

`POST /story-projects/{projectId}/cast-voice/design`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/story-projects/{projectId}/cast-voice/design`
- Auth: HTTP bearer

Draws up to four candidate voices for one named cast member (`character`, by canon name, alias or script cue) from `description`, or from the Series Bible's voice line for them when `description` is omitted, on the voice designer (ElevenLabs Voice Design). Each candidate is ONE TAKE of the CHARACTER'S OWN screenplay lines from this project (the design line, then `previewLines` more — and more of their lines when those are too short to clone a voice from), so each preview `url` is the character saying their own words; `sampleText` designs from a line of your own for a person with no lines yet. A description shorter than 20 characters is refused (400). A design never reuses a voice the character already has, so a redesign is never swallowed. TWO CALLS: sent without `confirmed` it PRICES the design and draws nothing (`quotedOnly: true`, `credits` — one casting voice per candidate, the price casting charges — `balanceAfter`, `sufficient`, `note`, and the `description`, `designLine` and `previewLines` it will use); sent again with `confirmed: true` it reserves, draws, and answers with `designId` and the `candidates`. EVERY CANDIDATE DRAWN IS CHARGED, chosen or not; choosing is free. Anyone on the project cast is reached, in an episode or not: a person with no lines in the screenplays (someone only a deck or trailer gives a line) is designed on `sampleText` — the line the deck gives them — or, without it, each take speaks a short passage the designer writes for the description (`designLine` is then null on the price). A key character's candidates are then judged by casting coverage by themselves, free (`coverage` on the answer; GET .../cast-voice/designs/{designId}/coverage). Then choose one with POST /story-projects/{projectId}/cast-voice/choose. Refused before the price with 409 `cast_voice_precondition_failed` when there is no description and no Series Bible voice line, or no voice designer is configured (`details.missing` `voice_design`); 409 `voice_retired` when the provider designed voices speak on has retired its voices; 409 `project_precondition_failed` when the project's gate holds spending.  Requires `Idempotency-Key`. Scope: `artifact:publish` (billable).

## Headers

- `Idempotency-Key` string, required

## Request body

- CastVoiceDesignRequest
  - `character` string, required: The cast member: canon name, alias or script cue.
  - `description` string: How the voice should sound. Omitted: the Series Bible's voice line for this person.
  - `candidates` integer: Candidate voices to draw (default 3). Each is charged.
  - `previewLines` integer: More of the character's lines each take speaks after the design line (default 2). When the lines are too short for a take to clone a voice from, more of their lines are added.
  - `sampleText` string: A line of your own to design on, for a person with no lines in the screenplays yet.
  - `gender` string
  - `age` string
  - `confirmed` boolean: Omit (or false) to get the price without spending anything. true draws the candidates, only after the writer has seen the price.

## Response `200`

The price (no `confirmed`) or the drawn candidates.

- CastVoiceDesignEnvelope: Quote: the price and the plan (`description`, `descriptionSource`, `candidates` as a count, `designLine`, `previewLines`). Confirmed: a CastVoiceDesign (`candidates` as the drawn list) with `credits` charged.
  - `quotedOnly` boolean, required
  - `credits` integer, required
  - `costLabel` string, nullable: Quote only.
  - `balanceAfter` integer: Quote only. Studio Credits the writer would have left once this is spent: the balance available now (as Billing shows it) minus the price. Negative means they are that many short.
  - `sufficient` boolean: Quote only. True when the available balance covers the price. False means the writer must top up first (the note names the Billing link) — do not confirm; the reserve would refuse.
  - `note` string, required: Show it to the writer. The quote says every candidate drawn is charged, chosen or not.
  - `character` string
  - `description` string
  - `descriptionSource` 'request' | 'series_bible': Quote only.
  - `designLine` object, nullable: Quote only: the line every take opens on. Null for a person with no lines in the screenplays and no `sampleText`: each take speaks a passage the designer writes for the description.
    - `text` string
    - `scriptUploadId` string, nullable
    - `entryIndex` integer, nullable
  - `previewLines` object[]: Quote only: the further lines every take speaks after the design line.
    - `text` string
    - `scriptUploadId` string
    - `entryIndex` integer
  - `candidates` union: Quote: how many will be drawn. Confirmed: the drawn candidates.
    - integer
    - object[]
  - `designId` string: Confirmed only.
  - `projectId` string: Confirmed only.
  - `createdAt` string, date-time: Confirmed only.
  - `chosen` object, nullable: Confirmed only (null until one is chosen).

## Other responses

- `400`: Request payload failed validation. The error message names the offending field.
- `401`: Missing, malformed, revoked, or expired API key.
- `402`: Not enough Studio Credits to reserve this job (`insufficient_credits`), and nothing was reserved. `details` is InsufficientCreditsDetails: `required` and `available`, and `autoTopup` when auto top-up is on but did not cover it — `pending` (retry in a moment), `over_cap` (raise the monthly spending cap), `too_small` (buy a bigger pack) or `failed`.
- `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.
- `409`: The read or project is not ready for this cast voice operation, and nothing was priced or charged (`cast_voice_precondition_failed`): no description and no Series Bible voice line, a character with no lines, nothing to restore, no finished recording to re-voice, a voice the character already speaks with, a finalize already running, or a recording that cannot be cut line by line. The message says which and what to do; `project_precondition_failed` when the project gate holds spending.
- `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)
