---
title: "Documents and speakers API"
description: "Every section has a versioned document of narration and dialogue blocks attributed to speakers. Read the document before editing it or generating audio, and list the project's speakers and casting."
canonical_url: https://lyricwinter.com/docs/api/documents
markdown_url: https://lyricwinter.com/docs/api/documents.md
last_updated: 2026-09-30
status: beta
---
# LyricWinter API reference: Documents and speakers

> Every section has a versioned document of narration and dialogue blocks attributed to speakers. Read the document before editing it or generating audio, and list the project's speakers and casting.

The LyricWinter API is in beta. Base URL: `https://lyricwinter.com/api/v1`. Authenticate every request with `Authorization: Bearer lw_...`. Successful responses are wrapped as `{ "data": ..., "request_id": "req_..." }`. Machine-readable contract: https://lyricwinter.com/api/v1/openapi.json.

## Endpoints

- [Get a section document](https://lyricwinter.com/docs/api/documents#get-studio-document): `GET /studio/sections/{sectionId}/document`
- [Edit a section document](https://lyricwinter.com/docs/api/documents#save-studio-document): `PATCH /studio/sections/{sectionId}/document`
- [Import a speaker-labeled script](https://lyricwinter.com/docs/api/documents#import-studio-script): `POST /studio/sections/{sectionId}/script`
- [List project speakers](https://lyricwinter.com/docs/api/documents#get-studio-project-speaker-usage): `GET /studio/projects/{projectId}/speakers`

### Get a section document

`GET /studio/sections/{sectionId}/document`

Scope: `studio:read` · Operation ID: `getStudioDocument`

Returns the section's current document: its `document_version`, blocks, the project's speakers and `speaker_registry_version`, and whether section sound effects are enabled. Read it before editing the section or generating audio.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `sectionId` | string, uuid | Yes |  |

#### Response 200

Canonical Studio document and optional recovery draft.

Fields inside `data`:

- `actor_user_id` (string, uuid; required): Authenticated caller; clients partition local recovery state by this ID.
- `project_id` (string, uuid; required)
- `document` (object; required): The canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks.
  - `blocks` (array of object, max 100000 items; required)
    - One of:
      - **kind: "speech"**
        - `block_version` (integer, > 0; required)
        - `content` (object; required)
          - `annotations` (array of object; required)
            - One of:
              - **kind: "exclusion"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("exclusion"; required)
                - `reason` (string, one of `speaker_label`, `stage_direction`, `metadata`, `user`; required)
                - `start_utf16` (integer, ≥ 0; required)
              - **kind: "pronunciation"**
                - `alphabet` (string, one of `ipa`, `x-sampa`, `cmu`, `alias`; required)
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("pronunciation"; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `value` (string, 1–500 chars; required)
              - **kind: "extension"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `payload` (object | null; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `version` (integer, > 0; required)
          - `delivery_control_sets` (array of object, max 32 items; required)
            - `capability_revision` (string, 1–200 chars; required)
            - `directives` (array of StudioAstDeliveryDirective, max 256 items; required)
            - `format` (string, one of `eleven-v4-1`, `inworld-tts2-1`, `inworld-tts2-experimental-1`, `inworld-tts15-max-1`, `inworld-tts15-mini-1`, `fish-s2-inline-1`, `fish-s2.1-inline-1`, `cartesia-sonic35-1`, `openai-gpt4o-mini-tts-1`, `openai-tts1-hd-1`, `openai-tts1-1`, `smallest-lightning31-1`, `chatterbox-classic-1`, `zyphra-zonos2-cloud-1`, `f5tts-v1-1`, `misotts-8b-1`; required)
            - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
            - `model` (string, 1–200 chars; required)
            - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
            - `provider_text_override` (string, 1–65536 chars, pattern [\s\S]*\S[\s\S]*; optional)
            - `schema_version` (string, one of `studio-delivery-control-set-1`, `studio-delivery-control-set-2`; required)
            - `settings` (array of StudioAstDeliverySetting, max 32 items; required)
            - `source_fingerprint` (string | null, pattern ^[0-9a-f]{64}$; required)
            - `source_utf16_length` (integer | null, ≥ 0; required)
          - `points` (array of object; required)
            - One of:
              - **kind: "timed_silence"**
                - `duration_ms` (integer, 1–300000; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("timed_silence"; required)
                - `offset_utf16` (integer, ≥ 0; required)
              - **kind: "extension"**
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `offset_utf16` (integer, ≥ 0; required)
                - `payload` (object | null; required)
                - `version` (integer, > 0; required)
          - `schema_version` ("studio-ast-2"; required)
          - `text` (string, max 65536 chars; required): Exact block text; at most 65,536 UTF-16 code units. Annotation, point, and delivery offsets are UTF-16 offsets into this string.
          - `type` ("text"; required)
        - `generation_profile_override` (object | null; required)
          - `controls` (string, one of `strict`, `best_effort`; optional)
          - `fallback` (string, one of `strict`, `best_effort`; optional)
          - `model` (string, 1–200 chars; optional)
          - `options` (map of boolean | string | integer | number | array of StudioAstJsonValue | map of StudioAstJsonValue | null; optional)
          - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; optional)
        - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `kind` ("speech"; required)
        - `placement` (any | null; required)
        - `speaker_id` (string | null, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
      - **kind: "narration"**
        - `block_version` (integer, > 0; required)
        - `content` (object; required)
          - `annotations` (array of object; required)
            - One of:
              - **kind: "exclusion"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("exclusion"; required)
                - `reason` (string, one of `speaker_label`, `stage_direction`, `metadata`, `user`; required)
                - `start_utf16` (integer, ≥ 0; required)
              - **kind: "pronunciation"**
                - `alphabet` (string, one of `ipa`, `x-sampa`, `cmu`, `alias`; required)
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("pronunciation"; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `value` (string, 1–500 chars; required)
              - **kind: "extension"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `payload` (object | null; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `version` (integer, > 0; required)
          - `delivery_control_sets` (array of object, max 32 items; required)
            - `capability_revision` (string, 1–200 chars; required)
            - `directives` (array of StudioAstDeliveryDirective, max 256 items; required)
            - `format` (string, one of `eleven-v4-1`, `inworld-tts2-1`, `inworld-tts2-experimental-1`, `inworld-tts15-max-1`, `inworld-tts15-mini-1`, `fish-s2-inline-1`, `fish-s2.1-inline-1`, `cartesia-sonic35-1`, `openai-gpt4o-mini-tts-1`, `openai-tts1-hd-1`, `openai-tts1-1`, `smallest-lightning31-1`, `chatterbox-classic-1`, `zyphra-zonos2-cloud-1`, `f5tts-v1-1`, `misotts-8b-1`; required)
            - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
            - `model` (string, 1–200 chars; required)
            - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
            - `provider_text_override` (string, 1–65536 chars, pattern [\s\S]*\S[\s\S]*; optional)
            - `schema_version` (string, one of `studio-delivery-control-set-1`, `studio-delivery-control-set-2`; required)
            - `settings` (array of StudioAstDeliverySetting, max 32 items; required)
            - `source_fingerprint` (string | null, pattern ^[0-9a-f]{64}$; required)
            - `source_utf16_length` (integer | null, ≥ 0; required)
          - `points` (array of object; required)
            - One of:
              - **kind: "timed_silence"**
                - `duration_ms` (integer, 1–300000; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("timed_silence"; required)
                - `offset_utf16` (integer, ≥ 0; required)
              - **kind: "extension"**
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `offset_utf16` (integer, ≥ 0; required)
                - `payload` (object | null; required)
                - `version` (integer, > 0; required)
          - `schema_version` ("studio-ast-2"; required)
          - `text` (string, max 65536 chars; required): Exact block text; at most 65,536 UTF-16 code units. Annotation, point, and delivery offsets are UTF-16 offsets into this string.
          - `type` ("text"; required)
        - `generation_profile_override` (object | null; required)
          - `controls` (string, one of `strict`, `best_effort`; optional)
          - `fallback` (string, one of `strict`, `best_effort`; optional)
          - `model` (string, 1–200 chars; optional)
          - `options` (map of boolean | string | integer | number | array of StudioAstJsonValue | map of StudioAstJsonValue | null; optional)
          - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; optional)
        - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `kind` ("narration"; required)
        - `placement` (any | null; required)
        - `speaker_id` (string | null, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
      - **kind: "unparsed"**
        - `block_version` (integer, > 0; required)
        - `content` (object; required)
          - `annotations` (array of object; required)
            - One of:
              - **kind: "exclusion"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("exclusion"; required)
                - `reason` (string, one of `speaker_label`, `stage_direction`, `metadata`, `user`; required)
                - `start_utf16` (integer, ≥ 0; required)
              - **kind: "pronunciation"**
                - `alphabet` (string, one of `ipa`, `x-sampa`, `cmu`, `alias`; required)
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("pronunciation"; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `value` (string, 1–500 chars; required)
              - **kind: "extension"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `payload` (object | null; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `version` (integer, > 0; required)
          - `delivery_control_sets` (array of object, max 32 items; required)
            - `capability_revision` (string, 1–200 chars; required)
            - `directives` (array of StudioAstDeliveryDirective, max 256 items; required)
            - `format` (string, one of `eleven-v4-1`, `inworld-tts2-1`, `inworld-tts2-experimental-1`, `inworld-tts15-max-1`, `inworld-tts15-mini-1`, `fish-s2-inline-1`, `fish-s2.1-inline-1`, `cartesia-sonic35-1`, `openai-gpt4o-mini-tts-1`, `openai-tts1-hd-1`, `openai-tts1-1`, `smallest-lightning31-1`, `chatterbox-classic-1`, `zyphra-zonos2-cloud-1`, `f5tts-v1-1`, `misotts-8b-1`; required)
            - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
            - `model` (string, 1–200 chars; required)
            - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
            - `provider_text_override` (string, 1–65536 chars, pattern [\s\S]*\S[\s\S]*; optional)
            - `schema_version` (string, one of `studio-delivery-control-set-1`, `studio-delivery-control-set-2`; required)
            - `settings` (array of StudioAstDeliverySetting, max 32 items; required)
            - `source_fingerprint` (string | null, pattern ^[0-9a-f]{64}$; required)
            - `source_utf16_length` (integer | null, ≥ 0; required)
          - `points` (array of object; required)
            - One of:
              - **kind: "timed_silence"**
                - `duration_ms` (integer, 1–300000; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("timed_silence"; required)
                - `offset_utf16` (integer, ≥ 0; required)
              - **kind: "extension"**
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `offset_utf16` (integer, ≥ 0; required)
                - `payload` (object | null; required)
                - `version` (integer, > 0; required)
          - `schema_version` ("studio-ast-2"; required)
          - `text` (string, max 65536 chars; required): Exact block text; at most 65,536 UTF-16 code units. Annotation, point, and delivery offsets are UTF-16 offsets into this string.
          - `type` ("text"; required)
        - `generation_profile_override` (object | null; required)
          - `controls` (string, one of `strict`, `best_effort`; optional)
          - `fallback` (string, one of `strict`, `best_effort`; optional)
          - `model` (string, 1–200 chars; optional)
          - `options` (map of boolean | string | integer | number | array of StudioAstJsonValue | map of StudioAstJsonValue | null; optional)
          - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; optional)
        - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `kind` ("unparsed"; required)
        - `placement` (any | null; required)
        - `speaker_id` (any | null; required)
      - **kind: "excluded"**
        - `block_version` (integer, > 0; required)
        - `content` (object; required)
          - `annotations` (array of object; required)
            - One of:
              - **kind: "exclusion"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("exclusion"; required)
                - `reason` (string, one of `speaker_label`, `stage_direction`, `metadata`, `user`; required)
                - `start_utf16` (integer, ≥ 0; required)
              - **kind: "pronunciation"**
                - `alphabet` (string, one of `ipa`, `x-sampa`, `cmu`, `alias`; required)
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("pronunciation"; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `value` (string, 1–500 chars; required)
              - **kind: "extension"**
                - `end_utf16` (integer, ≥ 0; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `payload` (object | null; required)
                - `start_utf16` (integer, ≥ 0; required)
                - `version` (integer, > 0; required)
          - `delivery_control_sets` (array of object, max 32 items; required)
            - `capability_revision` (string, 1–200 chars; required)
            - `directives` (array of StudioAstDeliveryDirective, max 256 items; required)
            - `format` (string, one of `eleven-v4-1`, `inworld-tts2-1`, `inworld-tts2-experimental-1`, `inworld-tts15-max-1`, `inworld-tts15-mini-1`, `fish-s2-inline-1`, `fish-s2.1-inline-1`, `cartesia-sonic35-1`, `openai-gpt4o-mini-tts-1`, `openai-tts1-hd-1`, `openai-tts1-1`, `smallest-lightning31-1`, `chatterbox-classic-1`, `zyphra-zonos2-cloud-1`, `f5tts-v1-1`, `misotts-8b-1`; required)
            - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
            - `model` (string, 1–200 chars; required)
            - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
            - `provider_text_override` (string, 1–65536 chars, pattern [\s\S]*\S[\s\S]*; optional)
            - `schema_version` (string, one of `studio-delivery-control-set-1`, `studio-delivery-control-set-2`; required)
            - `settings` (array of StudioAstDeliverySetting, max 32 items; required)
            - `source_fingerprint` (string | null, pattern ^[0-9a-f]{64}$; required)
            - `source_utf16_length` (integer | null, ≥ 0; required)
          - `points` (array of object; required)
            - One of:
              - **kind: "timed_silence"**
                - `duration_ms` (integer, 1–300000; required)
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("timed_silence"; required)
                - `offset_utf16` (integer, ≥ 0; required)
              - **kind: "extension"**
                - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `kind` ("extension"; required)
                - `name` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
                - `namespace` (string, pattern ^[a-z][a-z0-9_.-]{0,63}$; required)
                - `offset_utf16` (integer, ≥ 0; required)
                - `payload` (object | null; required)
                - `version` (integer, > 0; required)
          - `schema_version` ("studio-ast-2"; required)
          - `text` (string, max 65536 chars; required): Exact block text; at most 65,536 UTF-16 code units. Annotation, point, and delivery offsets are UTF-16 offsets into this string.
          - `type` ("text"; required)
        - `generation_profile_override` (object | null; required)
          - `controls` (string, one of `strict`, `best_effort`; optional)
          - `fallback` (string, one of `strict`, `best_effort`; optional)
          - `model` (string, 1–200 chars; optional)
          - `options` (map of boolean | string | integer | number | array of StudioAstJsonValue | map of StudioAstJsonValue | null; optional)
          - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; optional)
        - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `kind` ("excluded"; required)
        - `placement` (any | null; required)
        - `speaker_id` (any | null; required)
      - **kind: "note"**
        - `block_version` (integer, > 0; required)
        - `content` (object; required)
          - `schema_version` ("studio-ast-2"; required)
          - `text` (string, max 20000 chars; required)
          - `type` ("note"; required)
        - `generation_profile_override` (object | null; required)
          - `controls` (string, one of `strict`, `best_effort`; optional)
          - `fallback` (string, one of `strict`, `best_effort`; optional)
          - `model` (string, 1–200 chars; optional)
          - `options` (map of boolean | string | integer | number | array of StudioAstJsonValue | map of StudioAstJsonValue | null; optional)
          - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; optional)
        - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `kind` ("note"; required)
        - `placement` (any | null; required)
        - `speaker_id` (any | null; required)
      - **kind: "sfx"**
        - `block_version` (integer, > 0; required)
        - `content` (object; required)
          - `duration_ms` (integer, 100–300000; required)
          - `prompt` (string, 1–4000 chars; required)
          - `schema_version` ("studio-ast-2"; required)
          - `seed` (integer | null, ≥ -9007199254740991; required)
          - `type` ("sfx"; required)
          - `source` (object; optional): Present only when the SFX block plays an uploaded project sound; seed is then null.
            - `kind` ("project_sound"; required)
            - `sound_effect_id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
            - `sound_effect_revision_id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `generation_profile_override` (object | null; required)
          - `controls` (string, one of `strict`, `best_effort`; optional)
          - `fallback` (string, one of `strict`, `best_effort`; optional)
          - `model` (string, 1–200 chars; optional)
          - `options` (map of boolean | string | integer | number | array of StudioAstJsonValue | map of StudioAstJsonValue | null; optional)
          - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; optional)
        - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
        - `kind` ("sfx"; required)
        - `placement` (object; required)
          - `anchor` (object; required)
            - One of:
              - **kind: "block"**
                - `block_id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
                - `fraction` (number | null, 0–1; required)
                - `kind` ("block"; required)
                - `position` (string, one of `start`, `fraction`, `end`, `after`; required)
              - **kind: "section"**
                - `kind` ("section"; required)
                - `position` (string, one of `start`, `end`; required)
              - **kind: "unplaced"**
                - `kind` ("unplaced"; required)
          - `fade_in_ms` (integer, 0–300000; required)
          - `fade_out_ms` (integer, 0–300000; required)
          - `gain_db` (number, -60–24; required)
          - `offset_ms` (integer, -300000–300000; required)
        - `speaker_id` (any | null; required)
  - `different_speaker_gap_ms` (integer, 0–1000; required): Silence in milliseconds inserted between adjacent spoken blocks with different speakers.
  - `document_version` (integer, > 0; required)
  - `sfx_enabled` (boolean; required): Whether authored section sound effects are audible in playback and included in rendered exports. Legacy sections without a stored value report true.
  - `same_speaker_gap_ms` (integer, 0–1000; required): Silence in milliseconds inserted between adjacent spoken blocks with the same speaker.
  - `schema_version` ("studio-ast-2"; required)
  - `section_id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required): Canonical lowercase UUID of the section.
  - `speaker_registry_version` (integer, > 0; required): Project-wide speaker registry version the speakers list was read at.
  - `speakers` (array of object; required): Every active speaker in the project registry, not only speakers referenced by this section.
    - `generation_profile` (object | null; required)
      - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
      - `model` (string, 1–200 chars; required)
      - `fallback` (string, one of `strict`, `best_effort`; required)
      - `controls` (string, one of `strict`, `best_effort`; required)
      - `options` (object; required)
    - `id` (string, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
    - `name` (string, 1–200 chars; required)
    - `speaker_version` (integer, > 0; required)
    - `voice_id` (string | null, pattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$; required)
  - `title` (string, max 500 chars; required)
- `source_draft` (object | null; required): The caller's saved, uncommitted Advanced Source draft for this section, or null.
  - `source_text` (string; required)
  - `base_document_version` (integer, ≥ 1; required)
  - `base_speaker_registry_version` (integer, ≥ 1; required)
  - `base_speaker_versions` (map of integer; required): Speaker versions keyed by speaker ID when the draft began.
  - `diagnostics` (array of object, max 1000 items; required)
    - `code` (string, one of `INVALID_SOURCE`, `STALE_SOURCE`; required)
    - `message` (string, 1–2000 chars; required)
  - `updated_at` (string, date-time; required)

Errors: `400`, `401`, `403`, `404`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/studio/sections/$SECTION_ID/document" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Edit a section document

`PATCH /studio/sections/{sectionId}/document`

Scope: `studio:write` · Retries: reuse the same `client_mutation_id` · Operation ID: `saveStudioDocument`

Applies a batch of document commands against the versions you last read. The whole batch commits atomically; if any targeted version changed, the request fails with `409` and nothing is applied.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `sectionId` | string, uuid | Yes |  |

#### Request body (application/json, required)

- `schema_version` (1; required)
- `actor_session_id` (string, uuid; required)
- `client_mutation_id` (string, uuid; required)
- `base_document_version` (integer, ≥ 1; required)
- `base_speaker_registry_version` (integer, ≥ 1; required)
- `target_block_versions` (map of integer; required)
- `target_speaker_versions` (map of integer; required)
- `commands` (array of object, 1–1000 items; required)
  - One of:
    - **kind: "set_section_sfx_enabled"**
      - `kind` ("set_section_sfx_enabled"; required)
      - `sfx_enabled` (boolean; required): Whether authored section sound effects are audible in playback and included in rendered exports. Disabling preserves authored SFX blocks and renditions.
    - **Option 2**
      - `kind` (string; required)

#### Response 200

Authoritative document after commit or idempotent replay.

Fields inside `data`:

- `actor_user_id` (string, uuid; required): Authenticated caller; clients partition local recovery state by this ID.
- `project_id` (string, uuid; required)
- `document` (object; required): The canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks. See [Get a section document](https://lyricwinter.com/docs/api/documents#get-studio-document) for its fields.
- `source_draft` (object | null; required): The caller's saved, uncommitted Advanced Source draft for this section, or null.
  - `source_text` (string; required)
  - `base_document_version` (integer, ≥ 1; required)
  - `base_speaker_registry_version` (integer, ≥ 1; required)
  - `base_speaker_versions` (map of integer; required): Speaker versions keyed by speaker ID when the draft began.
  - `diagnostics` (array of object, max 1000 items; required)
    - `code` (string, one of `INVALID_SOURCE`, `STALE_SOURCE`; required)
    - `message` (string, 1–2000 chars; required)
  - `updated_at` (string, date-time; required)

Errors: `400`, `401`, `403`, `404`, `409`, `500` return the standard error envelope.

#### Example request

```bash
curl -X PATCH "https://lyricwinter.com/api/v1/studio/sections/$SECTION_ID/document" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "schema_version": 1,
  "actor_session_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
  "client_mutation_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
  "base_document_version": 1,
  "base_speaker_registry_version": 1,
  "target_block_versions": {},
  "target_speaker_versions": {},
  "commands": [
    {
      "kind": "set_section_sfx_enabled",
      "sfx_enabled": true
    }
  ]
}'
```

### Import a speaker-labeled script

`POST /studio/sections/{sectionId}/script`

Scope: `studio:write` · Retries: reuse the same `client_mutation_id` · Operation ID: `importStudioScript`

Turn `SPEAKER: [optional direction] spoken text` lines into a Studio document without building an AST. Map each speaker label to a voice and generation profile. A separate `(silence 4s)` line adds exact silence after the preceding spoken line. Unsupported lines or directions fail rather than disappearing. This replaces the section script; it does not generate audio. Send the current document and speaker-registry versions. Reusing an existing speaker name updates that project-wide speaker's voice and profile. Retry uncertain responses with the same mutation ID and body; a receipt that cannot be verified returns `409` without importing again.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `sectionId` | string, uuid | Yes |  |

#### Request body (application/json, required)

- `schema_version` (1; required)
- `actor_session_id` (string, uuid; required)
- `client_mutation_id` (string, uuid; required)
- `base_document_version` (integer, ≥ 1; required)
- `base_speaker_registry_version` (integer, ≥ 1; required)
- `script` (string, min 1 chars; required): One SPEAKER: [optional direction] spoken text per nonblank line. A separate (silence 4s) or (silence 4000ms) line adds 1-300 seconds of silence after the preceding spoken line. Labels match speaker-map keys exactly. Unsupported lines are rejected.
- `speakers` (map of object; required): Exact speaker-label keys used in the script, each with an explicit voice and generation profile. Existing project speakers with the same name are reused.
  - `voice_id` (string | null, uuid; required)
  - `generation_profile` (object; required)
    - `provider` (string, pattern ^[a-z][a-z0-9_-]{0,63}$; required)
    - `model` (string, 1–200 chars; required)
    - `fallback` (string, one of `strict`, `best_effort`; required)
    - `controls` (string, one of `strict`, `best_effort`; required)
    - `options` (object; required)

#### Response 200

Canonical Studio document after the import.

Fields inside `data`:

- `actor_user_id` (string, uuid; required): Authenticated caller; clients partition local recovery state by this ID.
- `project_id` (string, uuid; required)
- `document` (object; required): The canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks. See [Get a section document](https://lyricwinter.com/docs/api/documents#get-studio-document) for its fields.
- `source_draft` (object | null; required): The caller's saved, uncommitted Advanced Source draft for this section, or null.
  - `source_text` (string; required)
  - `base_document_version` (integer, ≥ 1; required)
  - `base_speaker_registry_version` (integer, ≥ 1; required)
  - `base_speaker_versions` (map of integer; required): Speaker versions keyed by speaker ID when the draft began.
  - `diagnostics` (array of object, max 1000 items; required)
    - `code` (string, one of `INVALID_SOURCE`, `STALE_SOURCE`; required)
    - `message` (string, 1–2000 chars; required)
  - `updated_at` (string, date-time; required)

Errors: `400`, `401`, `403`, `404`, `409`, `500` return the standard error envelope.

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/studio/sections/$SECTION_ID/script" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "schema_version": 1,
  "actor_session_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
  "client_mutation_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
  "base_document_version": 1,
  "base_speaker_registry_version": 1,
  "script": "string",
  "speakers": {}
}'
```

### List project speakers

`GET /studio/projects/{projectId}/speakers`

Scope: `studio:read` · Operation ID: `getStudioProjectSpeakerUsage`

Returns the project's speakers with how many lines and sections each one appears in, plus the current `speaker_registry_version`.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string, uuid | Yes |  |

#### Response 200

Project-wide character usage and current character registry authority.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `speaker_registry_version` (integer, ≥ 1; required)
- `speakers` (array of object, max 10000 items; required): Every active project speaker, including unused speakers with zero counts.
  - `speaker_id` (string, uuid; required)
  - `line_count` (integer, ≥ 0; required): Active speech and narration blocks assigned to the speaker across active sections.
  - `block_override_count` (integer, ≥ 0; required): Of those blocks, how many carry a block-level generation profile override.
  - `section_count` (integer, ≥ 0; required): Active sections containing at least one of those blocks.

Errors: `400`, `401`, `403`, `404`, `500` return the standard error envelope.

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/speakers" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

