---
title: "Judge a voice design's candidates again."
method: POST
path: "/story-projects/{projectId}/cast-voice/designs/{designId}/coverage"
tags: ["Projects"]
---

# Judge a voice design's candidates again.

`POST /story-projects/{projectId}/cast-voice/designs/{designId}/coverage`

## Request

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

Listens to the candidates again as a new casting coverage report, with the cast as it stands now. FREE to the writer: no price and no `confirmed`. Coverage already runs by itself once per key character's design; a report already running is returned as it is. Refused (400) for a design with no hosted takes, or when no provider can listen right now. Requires `Idempotency-Key`. Scope: `story:write`.

## Headers

- `Idempotency-Key` string, required

## Request body

- CastingCoverageGenerateRequest
  - `focusPrompt` string: Optional: what to listen for hardest this time.

## Response `200`

The report now running (or the one already running).

- CastingCoverageResponse
  - `coverage` CastingCoverage, required: CASTING COVERAGE of a cast voice design: a model listened to every candidate take blind, beside the voices already cast in the project, and scored each against the brief and the Series Bible. It runs by itself, free to the writer, when a key character's design is drawn. Choosing a candidate in `failingCandidates` is refused unless the writer chooses it anyway; a report still running, one that could not run, or an unavailable listener never holds a choice.
    - `status` 'missing' | 'generating' | 'complete' | 'failed', required
    - `kind` 'voice', required
    - `projectId` string, required
    - `designId` string, required
    - `character` string, required
    - `keyCharacter` boolean, required: A principal (by the Series Bible or by line count): judged by itself when a design is drawn.
    - `available` boolean, required: False when no provider can listen right now.
    - `gateThreshold` number, required
    - `vetoDimensions` string[], required
    - `distinctnessThreshold` number, required: Speaker-embedding similarity at or above which two voices count as the same speaker (`casting_coverage_policy`, 0.88 by default).
    - `recommended` integer, nullable, required: The best candidate that cleared the bar, on its own.
    - `cast` object, nullable, required: The design's place in the CAST PLAN: across every open design of the project, one candidate each so that no two — and none against a chosen voice — measure as the same speaker. `pick` is the candidate the set takes for this design; `conflicts` the better ones it passed over and who they sound like. Null without a complete, measured report.
      - `pick` integer, nullable
      - `feasible` boolean: True only when `pick` keeps every voice apart AND clears its own bar. False: no valid set — design again; `note` names the colliding pair.
      - `conflicts` object[]
        - `candidate` integer
        - `character` string
        - `similarity` number
      - `designs` integer
      - `note` string
    - `failingCandidates` integer[], required: Choosing one needs `acknowledgeCastingCoverage: true`.
    - `summary` string, required: One sentence to lead with.
    - `trigger` 'auto' | 'manual' | 'null', nullable, required
    - `reportId` string, nullable, required
    - `reportVersion` integer, nullable, required
    - `rubricVersion` integer, nullable, required
    - `model` string, nullable, required
    - `progressDetail` string, nullable, required
    - `failureMessage` string, nullable, required: Why the run stopped, as one plain sentence for the writer — never a provider's or the database's raw wording. Populated when `status: failed`.
    - `report` object, nullable, required
      - `kind` 'voice', required
      - `candidates` CastingCandidateCoverage[], required
        - `candidate` integer, required: The number POST .../cast-voice/choose takes.
        - `rank` number, nullable, required: Median place across the runs (1 = best).
        - `ranks` integer[]
        - `score` number, nullable, required: The weighted score the bar reads (0–10).
        - `passed` boolean, required
        - `recommended` boolean, required
        - `gateReasons` string[], required
        - `flags` string[], required: Short flags to lead with: failures first, then warnings.
        - `dimensions` object, required: emblematicFit, truthfulness, periodRegister, accentHonesty, artifacts, wordAccuracy, distinctness (null: not judged).
        - `transcript` string, nullable: What the take was heard to say, transcribed without the script.
        - `wordAccuracy` number, nullable: Share of the scripted words heard as written (0–1).
        - `misheard` string[]
        - `heardAs` object, nullable
          - `gender` string
          - `age` string
          - `accent` string
        - `strengths` string
        - `problems` object[]
          - `atSeconds` number
          - `note` string
        - `closestCastVoice` object, nullable
          - `character` string
          - `note` string
        - `speakerSimilarity` object[]: MEASURED speaker-embedding similarity (cosine 0–1) to every voice it was compared with, closest first (empty: embeddings unavailable).
          - `character` string
          - `source` 'chosen' | 'recommended'
          - `similarity` number
        - `soundsLike` object, nullable: A chosen voice of another character this candidate measures as the same speaker as (at or above `distinctnessThreshold`): it fails on its own.
          - `character` string
          - `similarity` number
        - `excerpt` object, nullable: The strongest 15–20 s of the take, on sentence boundaries.
          - `startSeconds` number
          - `endSeconds` number
      - `ranking` integer[], required: Every candidate, best first.
      - `recommended` integer, nullable, required
      - `runnerUp` integer, nullable, required
      - `close` boolean, required: The runner-up sat close to the recommendation: hear both.
      - `allFail` boolean, required
      - `redesign` object, nullable, required
        - `why` string
        - `revisedBrief` string: Design again from this (POST .../cast-voice/design with `description`).
      - `verdict` string, required
      - `references` object[], required
        - `character` string
        - `source` 'chosen' | 'recommended'
        - `designId` string
        - `candidate` integer
      - `judging` object, required: How it was reached: each run (its order, ranking, scores and cost), why it stopped, the extra-run spend, the fingerprint, and what was carried.
    - `createdAt` string, date-time, nullable, required
    - `updatedAt` string, date-time, nullable, required

## 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`: No cast voice design with that id in this project (`voice_design_not_found`), or the project is not yours (`project_not_found`).
- `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)
