---
title: "Re-voice one character in a finished table read (metered — TWO CALLS, price first)."
method: POST
path: "/artifacts/{artifactId}/revoice"
tags: ["Artifacts"]
---

# Re-voice one character in a finished table read (metered — TWO CALLS, price first).

`POST /artifacts/{artifactId}/revoice`

## Request

- Base URL: `https://docs.sleeperhit.studio/api/v1`
- URL: `https://docs.sleeperhit.studio/api/v1/artifacts/{artifactId}/revoice`
- Auth: HTTP bearer

Speaks only `character`'s lines again in a new voice and keeps every other line byte for byte from the recording the read already has, then mixes the read again with its music and sound (`TABLE_READ_REVOICE`, priced on GET /credits). The voice is `voiceId` (with `voiceName`/`provider`), or the cast canon voice for the person when omitted (after POST /story-projects/{projectId}/cast-voice/choose). The recast inside it pins the canon too and keeps the previous voice and recording restorable (POST .../voice/restore). TWO CALLS: sent without `confirmed` it PRICES the re-voice and changes nothing (`quotedOnly: true`, `credits`, `lines` and `chars` it speaks again, `keptLines`, `balanceAfter`, `sufficient`, and a `note` to show the writer; when `sufficient` is false the caller must not confirm); sent again with `confirmed: true` it reserves, recasts and queues the finalize. Poll GET /artifacts/{artifactId} until `manifest.audio.finalize.status` is `complete`; the credit settles only then and is released if it fails. Refused before the price with 409 `cast_voice_precondition_failed`: a read with no finished recording (recast and finalize instead), a character with no lines in it, a voice it already speaks with, a finalize already running, or a recording whose lines overlap (it cannot be cut line by line). Refused with 409 `voice_retired` when the new voice, or the voice of any line spoken again, is one its provider has retired; lines kept from the recording never count, so a cast on a retired provider can be moved off it one character at a time.  Requires `Idempotency-Key`. Scope: `artifact:publish`.

## Headers

- `Idempotency-Key` string, required

## Request body

- RevoiceRequest
  - `character` string, required: The character to re-voice: canon name, alias or script cue.
  - `voiceId` string: The new voice. Omitted: the cast canon voice for this person.
  - `voiceName` string
  - `provider` string
  - `gender` string
  - `confirmed` boolean: Omit (or false) to get the price without spending anything. true reserves and queues the re-voice, only after the writer has seen the price.

## Response `200`

The price (no `confirmed`) or the queued re-voice.

- RevoiceEnvelope
  - `quotedOnly` boolean, required: true when this call only PRICED the re-voice.
  - `artifactId` string, required
  - `character` string, required
  - `voice` object, required
    - `voiceId` string
    - `voiceName` string
    - `provider` string, nullable
  - `previousVoice` object, required
    - `voiceId` string, nullable
    - `voiceName` string, nullable
  - `lines` integer, required: The character's lines, spoken again.
  - `chars` integer, required
  - `keptLines` integer, required: Lines kept as they are in the current recording.
  - `resynthesizedLines` integer, required: Every line spoken again.
  - `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: The price and what it would leave (quote), or what happens next (confirmed). Show it to the writer.
  - `status` 'queued': Confirmed calls only. Poll GET /artifacts/{artifactId} until `manifest.audio.finalize.status` is complete.
  - `restore` RestorableVoice: A recast that POST /artifacts/{artifactId}/voice/restore can undo.
    - `character` string, required
    - `historyId` string, required
    - `at` string, date-time, required
    - `previousVoiceId` string, nullable, required: The voice a restore puts back; null when the character had none.
    - `previousVoiceName` string, nullable, required
    - `currentVoiceName` string, nullable, required
    - `recordingRecoverable` boolean, required: A restore also brings back the recording the read had before the recast.

## 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 story artifact 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)
