---
title: "Sections API"
description: "A section is one chapter or scene of story text inside a project. Create a standalone story with one section, add sections to a project, reorder them, or delete them."
canonical_url: https://lyricwinter.com/docs/api/sections
markdown_url: https://lyricwinter.com/docs/api/sections.md
last_updated: 2026-09-30
status: beta
---
# LyricWinter API reference: Sections

> A section is one chapter or scene of story text inside a project. Create a standalone story with one section, add sections to a project, reorder them, or delete them.

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

- [Create a standalone story](https://lyricwinter.com/docs/api/sections#create-standalone-studio-section): `POST /studio/sections`
- [List project sections](https://lyricwinter.com/docs/api/sections#list-studio-project-sections): `GET /studio/projects/{projectId}/sections`
- [Add a section to a project](https://lyricwinter.com/docs/api/sections#create-studio-section): `POST /studio/projects/{projectId}/sections`
- [Move a section](https://lyricwinter.com/docs/api/sections#move-studio-section): `PATCH /studio/projects/{projectId}/sections/{sectionId}`
- [Preview section deletion](https://lyricwinter.com/docs/api/sections#get-studio-section-deletion-info): `GET /studio/projects/{projectId}/sections/{sectionId}/deletion-info`
- [Delete a section](https://lyricwinter.com/docs/api/sections#delete-studio-section): `DELETE /studio/projects/{projectId}/sections/{sectionId}`

### Create a standalone story

`POST /studio/sections`

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

Creates a standalone Studio story with one section containing the exact text you send. Returns `201` with the new project ID, section, and document, or `200` with `idempotent_replay: true` when the same `client_mutation_id` was already applied.

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

- `schema_version` (1; required)
- `actor_session_id` (string, uuid; required)
- `client_mutation_id` (string, uuid; required): Idempotency key; a replay with the same canonical request returns the committed result.
- `title` (string, max 500 chars; required): At most 500 UTF-16 code units. Must not contain null characters or malformed Unicode.
- `raw_text` (string; required): Exact section text stored as one unparsed block. At most 8 MiB of UTF-8 (the whole request body is also limited to 8 MiB). Must not contain null characters or malformed Unicode.

#### Response 200

Idempotent replay of the existing standalone story.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `section` (object; required)
  - `id` (string, uuid; required)
  - `project_id` (string, uuid; required)
  - `title` (string; required)
  - `document_version` (integer, ≥ 1; required)
  - `source_text_length` (integer, ≥ 0; required): Length of the section's exact source-text projection in UTF-16 code units.
  - `activity_status` (string, one of `blank`, `working`, `needs_audio`, `audio_ready`, `audio_failed`; required): Navigator state: working (active workflow or pending audio), audio_failed (latest audio attempt failed), audio_ready (every generatable block has current audio and no unparsed text remains), needs_audio (generatable or unparsed text without complete current audio), or blank (nothing to generate).
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; 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.
- `section_order_version` (integer, ≥ 1; required)
- `speaker_registry_version` (integer, ≥ 1; required)
- `idempotent_replay` (boolean; required): True when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).

#### Response 201

Standalone Studio story created.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `section` (object; required)
  - `id` (string, uuid; required)
  - `project_id` (string, uuid; required)
  - `title` (string; required)
  - `document_version` (integer, ≥ 1; required)
  - `source_text_length` (integer, ≥ 0; required): Length of the section's exact source-text projection in UTF-16 code units.
  - `activity_status` (string, one of `blank`, `working`, `needs_audio`, `audio_ready`, `audio_failed`; required): Navigator state: working (active workflow or pending audio), audio_failed (latest audio attempt failed), audio_ready (every generatable block has current audio and no unparsed text remains), needs_audio (generatable or unparsed text without complete current audio), or blank (nothing to generate).
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; 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.
- `section_order_version` (integer, ≥ 1; required)
- `speaker_registry_version` (integer, ≥ 1; required)
- `idempotent_replay` (boolean; required): True when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).

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

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/studio/sections" \
  -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",
  "title": "Chapter One",
  "raw_text": "A bell rang. \"Who is there?\" Mira asked."
}'
```

### List project sections

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

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

Returns a project's sections in order with the project's `section_order_version` and `speaker_registry_version`. A project that has not been opened in Studio yet returns `initialized: false`.

#### Path parameters

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

#### Response 200

Studio project state and sections.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `initialized` (boolean; required): False when the owned project has no Studio state yet; the nullable fields are then null and sections is empty.
- `casting_defaults_mode` (string | null, one of `apply_exact`, `suggest`, `ignore`; required)
- `default_automation_profile` (string | null, one of `quick`, `balanced`, `directed`; required)
- `section_order_version` (integer | null, ≥ 1; required)
- `speaker_registry_version` (integer | null, ≥ 1; required)
- `sections` (array of object; required): Active sections in project order.
  - `id` (string, uuid; required)
  - `project_id` (string, uuid; required)
  - `title` (string; required)
  - `document_version` (integer, ≥ 1; required)
  - `source_text_length` (integer, ≥ 0; required): Length of the section's exact source-text projection in UTF-16 code units.
  - `activity_status` (string, one of `blank`, `working`, `needs_audio`, `audio_ready`, `audio_failed`; required): Navigator state: working (active workflow or pending audio), audio_failed (latest audio attempt failed), audio_ready (every generatable block has current audio and no unparsed text remains), needs_audio (generatable or unparsed text without complete current audio), or blank (nothing to generate).
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)

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

#### Example request

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

### Add a section to a project

`POST /studio/projects/{projectId}/sections`

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

Adds one section of unstructured text to a project. Send the `section_order_version` you last read as `base_section_order_version`; a stale version returns `409`.

#### Path parameters

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

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

- `schema_version` (1; required)
- `actor_session_id` (string, uuid; required)
- `client_mutation_id` (string, uuid; required): Idempotency key; a replay with the same canonical request returns the committed result.
- `base_section_order_version` (integer | null, ≥ 1; required): Section-order version the client last observed; null when the project has not initialized Studio.
- `title` (string, max 500 chars; required): At most 500 UTF-16 code units. Must not contain null characters or malformed Unicode.
- `raw_text` (string; required): Exact section text stored as one unparsed block. At most 8 MiB of UTF-8 (the whole request body is also limited to 8 MiB). Must not contain null characters or malformed Unicode.

#### Response 200

Idempotent replay of the existing section.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `section` (object; required)
  - `id` (string, uuid; required)
  - `project_id` (string, uuid; required)
  - `title` (string; required)
  - `document_version` (integer, ≥ 1; required)
  - `source_text_length` (integer, ≥ 0; required): Length of the section's exact source-text projection in UTF-16 code units.
  - `activity_status` (string, one of `blank`, `working`, `needs_audio`, `audio_ready`, `audio_failed`; required): Navigator state: working (active workflow or pending audio), audio_failed (latest audio attempt failed), audio_ready (every generatable block has current audio and no unparsed text remains), needs_audio (generatable or unparsed text without complete current audio), or blank (nothing to generate).
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; 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.
- `section_order_version` (integer, ≥ 1; required)
- `speaker_registry_version` (integer, ≥ 1; required)
- `idempotent_replay` (boolean; required): True when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).

#### Response 201

Studio section created.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `section` (object; required)
  - `id` (string, uuid; required)
  - `project_id` (string, uuid; required)
  - `title` (string; required)
  - `document_version` (integer, ≥ 1; required)
  - `source_text_length` (integer, ≥ 0; required): Length of the section's exact source-text projection in UTF-16 code units.
  - `activity_status` (string, one of `blank`, `working`, `needs_audio`, `audio_ready`, `audio_failed`; required): Navigator state: working (active workflow or pending audio), audio_failed (latest audio attempt failed), audio_ready (every generatable block has current audio and no unparsed text remains), needs_audio (generatable or unparsed text without complete current audio), or blank (nothing to generate).
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; 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.
- `section_order_version` (integer, ≥ 1; required)
- `speaker_registry_version` (integer, ≥ 1; required)
- `idempotent_replay` (boolean; required): True when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).

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

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/sections" \
  -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_section_order_version": 1,
  "title": "Chapter One",
  "raw_text": "A bell rang. \"Who is there?\" Mira asked."
}'
```

### Move a section

`PATCH /studio/projects/{projectId}/sections/{sectionId}`

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

Moves a section to a new position in the project. Send the current `section_order_version`; a stale version returns `409`.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string, uuid | Yes |  |
| `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): Idempotency key; a replay with the same canonical request returns the committed result.
- `base_section_order_version` (integer, ≥ 1; required)
- `to_index` (integer, 0–4999; required): Zero-based target index in the active section order.

#### Response 200

Section move committed or replayed.

Fields inside `data`:

- `operation` (string, one of `move_section`, `delete_section`; required): move_section for PATCH and delete_section for DELETE.
- `project_id` (string, uuid; required)
- `section_id` (string, uuid; required)
- `section_order_version` (integer, ≥ 1; required): Section-order version committed by this mutation.
- `idempotent_replay` (boolean; 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/projects/$PROJECT_ID/sections/$SECTION_ID" \
  -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_section_order_version": 1,
  "to_index": 1
}'
```

### Preview section deletion

`GET /studio/projects/{projectId}/sections/{sectionId}/deletion-info`

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

Returns counts of the script blocks, generated clips, and active share links that deleting the section would make inaccessible.

#### Path parameters

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

#### Response 200

Section deletion preview.

Fields inside `data`:

- `project_id` (string, uuid; required)
- `section_id` (string, uuid; required)
- `block_count` (integer, ≥ 0; required)
- `generated_clip_count` (integer, ≥ 0; required)
- `active_share_link_count` (integer, ≥ 0; required)

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

#### Example request

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

### Delete a section

`DELETE /studio/projects/{projectId}/sections/{sectionId}`

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

Deletes a section after checking both the section order version and the document version. This cannot be undone through the API.

#### Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string, uuid | Yes |  |
| `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): Idempotency key; a replay with the same canonical request returns the committed result.
- `base_section_order_version` (integer, ≥ 1; required)
- `base_document_version` (integer, ≥ 1; required)

#### Response 200

Section deletion committed or replayed.

Fields inside `data`:

- `operation` (string, one of `move_section`, `delete_section`; required): move_section for PATCH and delete_section for DELETE.
- `project_id` (string, uuid; required)
- `section_id` (string, uuid; required)
- `section_order_version` (integer, ≥ 1; required): Section-order version committed by this mutation.
- `idempotent_replay` (boolean; required)

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

#### Example request

```bash
curl -X DELETE "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/sections/$SECTION_ID" \
  -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_section_order_version": 1,
  "base_document_version": 1
}'
```

