---
title: "Read typed director's commentary in the director's voice and link each piece to its sound (costs credits)"
method: POST
path: "/v1/storyboards/{id}/director"
tags: ["Storyboards"]
---

# Read typed director's commentary in the director's voice and link each piece to its sound (costs credits)

`POST /v1/storyboards/{id}/director`

## Request

- Base URL: `https://nanostudiopro.com/api`
- URL: `https://nanostudiopro.com/api/v1/storyboards/{id}/director`
- Auth: HTTP bearer

The director's commentary (`doc.director`): the creator talking over the film, heard on the public `/watch` page only when the viewer turns it on (a switch, off by default, and a film sound / director balance). It is `tracks`, each on the path it was made on (`path`, decision id -> option id; absent: every path): a path that took another option at a decision at or before a piece's start does not hear it, one that takes another after its start cuts it at that decision, so a track on the shared start plays on every path until a decision cuts it. Each piece (`segments`) starts at a FILM second `fromS` on that path (the film's clock: a decision's wait does not count) and plays its `soundId` (a recording made on the page, or typed `text` read here) at `level` (0-2); the film's music, ambience and effects dip under it. Each typed piece named in `segment_ids`, else every one with words and no sound yet, is read by ElevenLabs text-to-speech (`eleven_multilingual_v2`) in the director's voice (`doc.director.voiceId`, else the default), brought to -20 LUFS, added to the film's sounds (kind `voice`) and linked to its piece. Free by hand: `{op: "addDirectorSegment", trackId, path?, segment: {id, fromS, text?, soundId?, level?}}` (a new `trackId` makes the track with that `path`; an existing one keeps its own), `updateDirectorSegment {id, patch: {fromS?, text?, soundId?, level?}}` (new words unlink a read sound, never a recording; null clears), `removeDirectorSegment {id}`, `setDirectorVoice {voiceId | null}`. Recording with a microphone is the page's alone. **Costs credits**: `audio_voice_100char` per 100 characters, the voice-over's price (see `/v1/pricing`). Quote first with `dry_run: true`: `credits`, each piece's `characters` and `credits`, the voice, and `voices`, the voice ids on offer. Without `dry_run` it answers `202 { task_id }`: poll `GET /v1/tasks/{id}`. Each piece is charged once its sound is on the storyboard, through your token so its daily cap applies. Paid tier only (`402 audio_requires_purchase` on trial credits). A storyboard whose owner approves agent spending answers `403` except for the quote.

## Request body

- object
  - `segment_ids` string[]
  - `dry_run` boolean

## Response `200`

The quote (dry_run)

- object
  - `dry_run` boolean
  - `available` boolean
  - `reason` string
  - `credits` integer
  - `per_100_chars` integer
  - `model` string
  - `segments` object[]
    - `segment_id` string
    - `characters` integer
    - `credits` integer
  - `voice_id` string
  - `voice_name` string, nullable
  - `voices` object[]
    - `voice_id` string
    - `name` string
    - `description` string
  - `running_task_id` string, nullable

## Other responses

- `202`: The run started
- `400`: That commentary has no words to read
- `401`: Missing or invalid token
- `402`: Insufficient credits
- `403`: The owner approves an agent's spending on this storyboard
- `409`: The commentary is being read for this film already
- `429`: Rate limit exceeded

---

[API](https://skmtc.dev/nanostudiopro/apis/nano-studio-pro-api.md) · [All operations](https://skmtc.dev/nanostudiopro/apis/nano-studio-pro-api/llms.txt) · [OpenAPI document](https://skmtc.dev/nanostudiopro/apis/nano-studio-pro-api/revisions/b454211e598e?raw)
