API reference
Sections API
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.
BetaUpdated
- Base URL
- https://lyricwinter.com/api/v1
- Authentication
- Authorization: Bearer lw_…
- Contract
- openapi.json
Create a standalone story
POST/studio/sections
studio:writeRetry with the same client_mutation_idCreates 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
schema_version1requiredactor_session_idstringrequireduuidclient_mutation_idstringrequireduuidIdempotency key; a replay with the same canonical request returns the committed result.
titlestringrequiredmax 500 charsAt most 500 UTF-16 code units. Must not contain null characters or malformed Unicode.
raw_textstringrequiredExact 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 below are inside data.
project_idstringrequireduuidsectionobjectrequired11 child attributes
last_opened_atstring | nulldate-timehas_audiobooleanPresent, and true, only with activity_status needs_audio: at least one line already has finished audio, so the section needs updating or finishing rather than creating.
idstringrequireduuidproject_idstringrequireduuidtitlestringrequireddocument_versionintegerrequired≥ 1source_text_lengthintegerrequired≥ 0Length of the section's exact source-text projection in UTF-16 code units.
source_word_countinteger≥ 0Word count of the saved source text using Unicode word segmentation. Includes text excluded from narration; sound prompts and notes are not source text. Omitted when unavailable.
activity_statusstringrequiredNavigator 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).
One of
blankworkingneeds_audioaudio_readyaudio_failedcreated_atstringrequireddate-timeupdated_atstringrequireddate-time
documentobjectrequiredThe canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks.
Full shape: Get a section document
section_order_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1idempotent_replaybooleanrequiredTrue 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 below are inside data.
project_idstringrequireduuidsectionobjectrequired11 child attributes
last_opened_atstring | nulldate-timehas_audiobooleanPresent, and true, only with activity_status needs_audio: at least one line already has finished audio, so the section needs updating or finishing rather than creating.
idstringrequireduuidproject_idstringrequireduuidtitlestringrequireddocument_versionintegerrequired≥ 1source_text_lengthintegerrequired≥ 0Length of the section's exact source-text projection in UTF-16 code units.
source_word_countinteger≥ 0Word count of the saved source text using Unicode word segmentation. Includes text excluded from narration; sound prompts and notes are not source text. Omitted when unavailable.
activity_statusstringrequiredNavigator 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).
One of
blankworkingneeds_audioaudio_readyaudio_failedcreated_atstringrequireddate-timeupdated_atstringrequireddate-time
documentobjectrequiredThe canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks.
Full shape: Get a section document
section_order_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1idempotent_replaybooleanrequiredTrue when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).
Errors 400, 401, 409, 500 use the standard error envelope.
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."
}'const response = await fetch(`https://lyricwinter.com/api/v1/studio/sections`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"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."
}),
});
const { data, error, request_id } = await response.json();import os
import requests
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/sections",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"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."
},
)
payload = response.json(){
"data": {
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"section": {
"last_opened_at": "2026-09-30T17:00:00.000Z",
"has_audio": true,
"id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"project_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"title": "Chapter One",
"document_version": 1,
"source_text_length": 1,
"source_word_count": 1,
"activity_status": "blank",
"created_at": "2026-09-30T17:00:00.000Z",
"updated_at": "2026-09-30T17:00:00.000Z"
},
"document": {
"blocks": [],
"different_speaker_gap_ms": 1,
"document_version": 1,
"sfx_enabled": true,
"same_speaker_gap_ms": 1,
"schema_version": "studio-ast-2",
"section_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"speaker_registry_version": 1,
"speakers": [],
"title": "Chapter One"
},
"section_order_version": 1,
"speaker_registry_version": 1,
"idempotent_replay": true
},
"request_id": "req_01J9Z3K8QF4"
}List project sections
GET/studio/projects/{projectId}/sections
studio:readReturns a project's sections in order with the project's section_order_version and speaker_registry_version. Section summaries include source_word_count when available: the word count of saved source text, including text excluded from narration. A project that has not been opened in Studio yet returns initialized: false.
Path parameters
projectIdstringrequireduuid
Response 200
Studio project state and sections. Fields below are inside data.
project_idstringrequireduuidinitializedbooleanrequiredFalse when the owned project has no Studio state yet; the nullable fields are then null and sections is empty.
casting_defaults_modestring | nullrequiredOne of
apply_exactsuggestignoredefault_automation_profilestring | nullrequiredOne of
quickbalanceddirectedsection_order_versioninteger | nullrequired≥ 1speaker_registry_versioninteger | nullrequired≥ 1sectionsarray of objectrequiredActive sections in project order.
11 item attributes
last_opened_atstring | nulldate-timehas_audiobooleanPresent, and true, only with activity_status needs_audio: at least one line already has finished audio, so the section needs updating or finishing rather than creating.
idstringrequireduuidproject_idstringrequireduuidtitlestringrequireddocument_versionintegerrequired≥ 1source_text_lengthintegerrequired≥ 0Length of the section's exact source-text projection in UTF-16 code units.
source_word_countinteger≥ 0Word count of the saved source text using Unicode word segmentation. Includes text excluded from narration; sound prompts and notes are not source text. Omitted when unavailable.
activity_statusstringrequiredNavigator 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).
One of
blankworkingneeds_audioaudio_readyaudio_failedcreated_atstringrequireddate-timeupdated_atstringrequireddate-time
Errors 400, 401, 403, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/sections" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const projectId = "<projectId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/sections`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/sections",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"initialized": true,
"casting_defaults_mode": "apply_exact",
"default_automation_profile": "quick",
"section_order_version": 1,
"speaker_registry_version": 1,
"sections": [
{
"last_opened_at": "2026-09-30T17:00:00.000Z",
"has_audio": true,
"id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"project_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"title": "Chapter One",
"document_version": 1,
"source_text_length": 1,
"source_word_count": 1,
"activity_status": "blank",
"created_at": "2026-09-30T17:00:00.000Z",
"updated_at": "2026-09-30T17:00:00.000Z"
}
]
},
"request_id": "req_01J9Z3K8QF4"
}Add a section to a project
POST/studio/projects/{projectId}/sections
studio:writeRetry with the same client_mutation_idAdds one section of unstructured text to a project. Standalone projects allow only one active section; adding another returns 400 STUDIO_COMMAND_REJECTED. Use a named project created through POST /projects for multiple sections. Send the section_order_version you last read as base_section_order_version; a stale version returns 409.
Path parameters
projectIdstringrequireduuid
Request body application/json
schema_version1requiredactor_session_idstringrequireduuidclient_mutation_idstringrequireduuidIdempotency key; a replay with the same canonical request returns the committed result.
base_section_order_versioninteger | nullrequired≥ 1Section-order version the client last observed; null when the project has not initialized Studio.
titlestringrequiredmax 500 charsAt most 500 UTF-16 code units. Must not contain null characters or malformed Unicode.
raw_textstringrequiredExact 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 below are inside data.
project_idstringrequireduuidsectionobjectrequired11 child attributes
last_opened_atstring | nulldate-timehas_audiobooleanPresent, and true, only with activity_status needs_audio: at least one line already has finished audio, so the section needs updating or finishing rather than creating.
idstringrequireduuidproject_idstringrequireduuidtitlestringrequireddocument_versionintegerrequired≥ 1source_text_lengthintegerrequired≥ 0Length of the section's exact source-text projection in UTF-16 code units.
source_word_countinteger≥ 0Word count of the saved source text using Unicode word segmentation. Includes text excluded from narration; sound prompts and notes are not source text. Omitted when unavailable.
activity_statusstringrequiredNavigator 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).
One of
blankworkingneeds_audioaudio_readyaudio_failedcreated_atstringrequireddate-timeupdated_atstringrequireddate-time
documentobjectrequiredThe canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks.
Full shape: Get a section document
section_order_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1idempotent_replaybooleanrequiredTrue when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).
Response 201
Studio section created. Fields below are inside data.
project_idstringrequireduuidsectionobjectrequired11 child attributes
last_opened_atstring | nulldate-timehas_audiobooleanPresent, and true, only with activity_status needs_audio: at least one line already has finished audio, so the section needs updating or finishing rather than creating.
idstringrequireduuidproject_idstringrequireduuidtitlestringrequireddocument_versionintegerrequired≥ 1source_text_lengthintegerrequired≥ 0Length of the section's exact source-text projection in UTF-16 code units.
source_word_countinteger≥ 0Word count of the saved source text using Unicode word segmentation. Includes text excluded from narration; sound prompts and notes are not source text. Omitted when unavailable.
activity_statusstringrequiredNavigator 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).
One of
blankworkingneeds_audioaudio_readyaudio_failedcreated_atstringrequireddate-timeupdated_atstringrequireddate-time
documentobjectrequiredThe canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks.
Full shape: Get a section document
section_order_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1idempotent_replaybooleanrequiredTrue when client_mutation_id matched an already committed creation (HTTP 200); false for a new section (HTTP 201).
Errors 400, 401, 403, 409, 500 use the standard error envelope.
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."
}'const projectId = "<projectId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/sections`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"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."
}),
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/sections",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"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."
},
)
payload = response.json(){
"data": {
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"section": {
"last_opened_at": "2026-09-30T17:00:00.000Z",
"has_audio": true,
"id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"project_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"title": "Chapter One",
"document_version": 1,
"source_text_length": 1,
"source_word_count": 1,
"activity_status": "blank",
"created_at": "2026-09-30T17:00:00.000Z",
"updated_at": "2026-09-30T17:00:00.000Z"
},
"document": {
"blocks": [],
"different_speaker_gap_ms": 1,
"document_version": 1,
"sfx_enabled": true,
"same_speaker_gap_ms": 1,
"schema_version": "studio-ast-2",
"section_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"speaker_registry_version": 1,
"speakers": [],
"title": "Chapter One"
},
"section_order_version": 1,
"speaker_registry_version": 1,
"idempotent_replay": true
},
"request_id": "req_01J9Z3K8QF4"
}Move a section
PATCH/studio/projects/{projectId}/sections/{sectionId}
studio:writeRetry with the same client_mutation_idMoves a section to a new position in the project. Send the current section_order_version; a stale version returns 409.
Path parameters
projectIdstringrequireduuidsectionIdstringrequireduuid
Request body application/json
schema_version1requiredactor_session_idstringrequireduuidclient_mutation_idstringrequireduuidIdempotency key; a replay with the same canonical request returns the committed result.
base_section_order_versionintegerrequired≥ 1to_indexintegerrequired0–4999Zero-based target index in the active section order.
Response 200
Section move committed or replayed. Fields below are inside data.
operationstringrequiredmove_section for PATCH and delete_section for DELETE.
One of
move_sectiondelete_sectionproject_idstringrequireduuidsection_idstringrequireduuidsection_order_versionintegerrequired≥ 1Section-order version committed by this mutation.
idempotent_replaybooleanrequired
Errors 400, 401, 403, 404, 409, 500 use the standard error envelope.
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
}'const projectId = "<projectId>";
const sectionId = "<sectionId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/sections/${sectionId}`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"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
}),
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
section_id = "<sectionId>"
response = requests.request(
"PATCH",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/sections/{section_id}",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"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
},
)
payload = response.json(){
"data": {
"operation": "move_section",
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"section_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_order_version": 1,
"idempotent_replay": true
},
"request_id": "req_01J9Z3K8QF4"
}Preview section deletion
GET/studio/projects/{projectId}/sections/{sectionId}/deletion-info
studio:readReturns counts of the script blocks, generated clips, and active share links that deleting the section would make inaccessible.
Path parameters
projectIdstringrequireduuidsectionIdstringrequireduuid
Response 200
Section deletion preview. Fields below are inside data.
project_idstringrequireduuidsection_idstringrequireduuidblock_countintegerrequired≥ 0generated_clip_countintegerrequired≥ 0active_share_link_countintegerrequired≥ 0
Errors 400, 401, 403, 404, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/sections/$SECTION_ID/deletion-info" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const projectId = "<projectId>";
const sectionId = "<sectionId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/sections/${sectionId}/deletion-info`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
section_id = "<sectionId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/sections/{section_id}/deletion-info",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"section_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"block_count": 1,
"generated_clip_count": 1,
"active_share_link_count": 1
},
"request_id": "req_01J9Z3K8QF4"
}Delete a section
DELETE/studio/projects/{projectId}/sections/{sectionId}
studio:writeRetry with the same client_mutation_idDeletes a section after checking both the section order version and the document version. This cannot be undone through the API.
Path parameters
projectIdstringrequireduuidsectionIdstringrequireduuid
Request body application/json
schema_version1requiredactor_session_idstringrequireduuidclient_mutation_idstringrequireduuidIdempotency key; a replay with the same canonical request returns the committed result.
base_section_order_versionintegerrequired≥ 1base_document_versionintegerrequired≥ 1
Response 200
Section deletion committed or replayed. Fields below are inside data.
operationstringrequiredmove_section for PATCH and delete_section for DELETE.
One of
move_sectiondelete_sectionproject_idstringrequireduuidsection_idstringrequireduuidsection_order_versionintegerrequired≥ 1Section-order version committed by this mutation.
idempotent_replaybooleanrequired
Errors 400, 401, 403, 404, 409, 500 use the standard error envelope.
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
}'const projectId = "<projectId>";
const sectionId = "<sectionId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/sections/${sectionId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"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
}),
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
section_id = "<sectionId>"
response = requests.request(
"DELETE",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/sections/{section_id}",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"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
},
)
payload = response.json(){
"data": {
"operation": "move_section",
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"section_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_order_version": 1,
"idempotent_replay": true
},
"request_id": "req_01J9Z3K8QF4"
}Read a story in one request
GET/studio/projects/{projectId}/story
studio:readRead all ordered sections with full documents and text, cast, per-block audio freshness, Studio play links, the five newest existing section exports, and the newest project export. Export artifacts include signed download links when available; inspect status, authority and expiry. This operation never generates audio, starts exports or creates shares. It aggregates authorized reads; it is not a cross-section transactional snapshot.
Path parameters
projectIdstringrequireduuid
Response 200
Read-only story state. Fields below are inside data.
project_idstringrequireduuidinitializedbooleanrequiredFalse when the owned project has no Studio state yet; the nullable fields are then null and sections is empty.
casting_defaults_modestring | nullrequiredOne of
apply_exactsuggestignoredefault_automation_profilestring | nullrequiredOne of
quickbalanceddirectedsection_order_versioninteger | nullrequired≥ 1speaker_registry_versioninteger | nullrequired≥ 1sectionsarray of objectrequired6 item attributes
summaryobjectrequired11 child attributes
last_opened_atstring | nulldate-timehas_audiobooleanPresent, and true, only with activity_status needs_audio: at least one line already has finished audio, so the section needs updating or finishing rather than creating.
idstringrequireduuidproject_idstringrequireduuidtitlestringrequireddocument_versionintegerrequired≥ 1source_text_lengthintegerrequired≥ 0Length of the section's exact source-text projection in UTF-16 code units.
source_word_countinteger≥ 0Word count of the saved source text using Unicode word segmentation. Includes text excluded from narration; sound prompts and notes are not source text. Omitted when unavailable.
activity_statusstringrequiredNavigator 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).
One of
blankworkingneeds_audioaudio_readyaudio_failedcreated_atstringrequireddate-timeupdated_atstringrequireddate-time
documentobjectrequiredThe canonical structured script of one section (studio-ast-2): its versions, speakers, and ordered blocks.
Full shape: Get a section document
textstringrequiredmediaobjectrequiredCurrent per-block media state for a Studio section.
3 child attributes
section_idstringrequireduuidplayback_duration_msinteger | nullrequired≥ 0Duration of the newest saved render manifest for the section's current document and speaker-registry versions; null when none exists.
blocksarray of objectrequiredOne entry per document block, in document order.
18 item attributes
block_idstringrequireduuidfreshnessstringrequiredabsent: no active rendition. current: the active rendition matches the block's current generation intent. stale: it differs (see stale_reasons). unsupported: the block kind is not speech, narration, or sfx.
One of
absentcurrentstaleunsupportedactivitystringrequiredgenerating: a pending rendition is queued, running, or waiting to retry, or imported audio is being copied. failed: the latest request or import failed. idle otherwise. Independent of freshness.
One of
idlegeneratingfailedactive_block_versioninteger | nullrequired≥ 1Block version the active rendition was requested for.
requested_block_versioninteger | nullrequired≥ 1Block version of the pending rendition or import, if any.
active_rendition_idstring | nullrequireduuidaudio_version_countintegerrequired≥ 0Number of completed audio versions for the block.
generation_batch_idstring | nullrequireduuidGeneration batch of the pending rendition.
playback_urlstring | nullrequireduriShort-lived signed URL for the active rendition's audio; null without an active asset.
playback_url_expires_atstring | nullrequireddate-timecontent_typestring | nullrequiredsize_bytesinteger | nullrequired≥ 1analysis_integrated_lufsnumber | nullrequired-120–24analysis_sample_peak_dbfsnumber | nullrequired-200–24providerstring | nullrequiredProvider that actually produced the active rendition (stored metadata for imports).
modelstring | nullrequiredModel that actually produced the active rendition (stored metadata for imports).
errorstring | nullrequiredLatest generation or import error message.
stale_reasonsarray of stringPresent for speech, narration, and sfx blocks; non-empty only when freshness is stale.
One of
block_kindtextpronunciationexcluded_texttimingvoicegeneration_profiledelivery_controlssound_effect
play_urlstringrequiredurilatest_exportsarray of objectrequiredmax 5 items15 item attributes
schema_version1requiredidstringrequireduuidproject_idstringrequireduuidsection_idstringrequireduuidformatstringrequiredOne of
mp3wavm4bepubsrtstatusstringrequiredOne of
queuedrunningretry_waitcancelingcompletedfailedcancelledsupersededphasestringrequiredOne of
queuedcompilingclaiming_artifactdownloadingmixingencodingpackaginguploadingcompletefailedcancelledpercentintegerrequired0–100cache_resultstringrequiredOne of
missreusedcoalescedauthorityobjectrequired4 child attributes
document_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1mastering_versionintegerrequired≥ 1is_currentbooleanrequired
created_atstringrequireddate-timestarted_atstring | nullrequireddate-timecompleted_atstring | nullrequireddate-timeerrorobject | nullrequired2 child attributes
codestringrequiredmessagestringrequired
artifactobject | nullrequired7 child attributes
asset_idstringrequireduuidfilenamestringrequired1–255 charscontent_typestringrequiredmin 1 charssize_bytesintegerrequired≥ 1download_urlstringrequireduridownload_url_expires_atstringrequireddate-timeartifact_expires_atstringrequireddate-time
schema_version1requiredplay_urlstringrequireduricastarray of object | nullrequiredNull when the story has no live section; read list_project_speakers for its retained characters.
5 item attributes
generation_profileobject | nullrequiredSaved profile read shape, including historical options. For new full-profile requests use StudioGenerationProfileRequest; its provider/model branches list accepted option keys. Generation eligibility and actual audio readiness are separate reads.
5 child attributes
providerstringrequiredpattern ^[a-z][a-z0-9_-]{0,63}$modelstringrequired1–200 charsfallbackstringrequiredOne of
strictbest_effortcontrolsstringrequiredOne of
strictbest_effortoptionsobjectrequired
idstringrequiredpattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$namestringrequired1–200 charsspeaker_versionintegerrequired> 0voice_idstring | nullrequiredpattern ^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
latest_project_exportsarray of objectrequiredmax 1 items9 item attributes
schema_version1requiredidstringrequireduuidParent project export job ID.
project_idstringrequireduuidformatstringrequiredOne of
mp3wavm4bepubsrtstatusstringrequiredqueued when all children are queued; running while any child is active otherwise. Once all children are terminal or unavailable: completed if all succeeded, partial_failed if only some succeeded, or failed if none succeeded. Child cancellation, supersession, and unavailability count as failure, not successful completion.
One of
queuedrunningcompletedpartial_failedfailedpercentintegerrequired0–100Floor of the mean child progress. Each terminal or unavailable child counts as 100, including failed, cancelled, or superseded children. Measures finished work, not success rate.
created_atstringrequireddate-timesectionsarray of objectrequired1–100 itemsImmutable selection and authority version plan in captured project order, with available child states or per-section unavailability errors.
6 item attributes
section_idstringrequireduuidtitlestringrequiredmax 500 charsSection title captured for this parent.
export_idstringrequireduuidCaptured child ID. Child status, manifest, and cancellation endpoints are usable only while the child remains accessible.
authorityobjectrequiredImmutable saved versions captured at enqueue, retained even if the child is moved or deleted.
3 child attributes
document_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1mastering_versionintegerrequired≥ 1
exportobject | nullrequiredCurrent ordinary child export payload, or null when the child is unavailable after transfer or deletion.
15 child attributes
schema_version1requiredidstringrequireduuidproject_idstringrequireduuidsection_idstringrequireduuidformatstringrequiredOne of
mp3wavm4bepubsrtstatusstringrequiredOne of
queuedrunningretry_waitcancelingcompletedfailedcancelledsupersededphasestringrequiredOne of
queuedcompilingclaiming_artifactdownloadingmixingencodingpackaginguploadingcompletefailedcancelledpercentintegerrequired0–100cache_resultstringrequiredOne of
missreusedcoalescedauthorityobjectrequired4 child attributes
document_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1mastering_versionintegerrequired≥ 1is_currentbooleanrequired
created_atstringrequireddate-timestarted_atstring | nullrequireddate-timecompleted_atstring | nullrequireddate-timeerrorobject | nullrequired2 child attributes
codestringrequiredmessagestringrequired
artifactobject | nullrequired7 child attributes
asset_idstringrequireduuidfilenamestringrequired1–255 charscontent_typestringrequiredmin 1 charssize_bytesintegerrequired≥ 1download_urlstringrequireduridownload_url_expires_atstringrequireddate-timeartifact_expires_atstringrequireddate-time
errorobject | nullrequiredPer-section availability error, or null when the child is available. Unavailable children report STUDIO_PROJECT_EXPORT_SECTION_UNAVAILABLE and count as aggregate failure.
2 child attributes
codestringrequiredmin 1 charsmessagestringrequired
archiveany | nullrequiredNo combined archive or ZIP is produced. Download child artifacts individually.
Errors 400, 401, 403, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/story" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const projectId = "<projectId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/story`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/story",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"initialized": true,
"casting_defaults_mode": "apply_exact",
"default_automation_profile": "quick",
"section_order_version": 1,
"speaker_registry_version": 1,
"sections": [
{
"summary": {
"last_opened_at": "2026-09-30T17:00:00.000Z",
"has_audio": true,
"id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"project_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"title": "Chapter One",
"document_version": 1,
"source_text_length": 1,
"source_word_count": 1,
"activity_status": "blank",
"created_at": "2026-09-30T17:00:00.000Z",
"updated_at": "2026-09-30T17:00:00.000Z"
},
"document": {
"blocks": [],
"different_speaker_gap_ms": 1,
"document_version": 1,
"sfx_enabled": true,
"same_speaker_gap_ms": 1,
"schema_version": "studio-ast-2",
"section_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"speaker_registry_version": 1,
"speakers": [],
"title": "Chapter One"
},
"text": "A bell rang. \"Who is there?\" Mira asked.",
"media": {
"section_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"playback_duration_ms": 1,
"blocks": [
{
"block_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"freshness": "absent",
"activity": "idle",
"active_block_version": 1,
"requested_block_version": 1,
"active_rendition_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"audio_version_count": 1,
"generation_batch_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"playback_url": "https://lyricwinter.com/…",
"playback_url_expires_at": "2026-09-30T17:00:00.000Z",
"content_type": "string",
"size_bytes": 1,
"analysis_integrated_lufs": -120,
"analysis_sample_peak_dbfs": -200,
"provider": "string",
"model": "string",
"error": "string",
"stale_reasons": [
"block_kind"
]
}
]
},
"play_url": "https://lyricwinter.com/…",
"latest_exports": [
{
"schema_version": 1,
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"project_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"format": "mp3",
"status": "queued",
"phase": "queued",
"percent": 1,
"cache_result": "miss",
"authority": {
"document_version": 1,
"speaker_registry_version": 1,
"mastering_version": 1,
"is_current": true
},
"created_at": "2026-09-30T17:00:00.000Z",
"started_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"error": {
"code": "string",
"message": "string"
},
"artifact": {
"asset_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"filename": "string",
"content_type": "string",
"size_bytes": 1,
"download_url": "https://lyricwinter.com/…",
"download_url_expires_at": "2026-09-30T17:00:00.000Z",
"artifact_expires_at": "2026-09-30T17:00:00.000Z"
}
}
]
}
],
"schema_version": 1,
"play_url": "https://lyricwinter.com/…",
"cast": [
{
"generation_profile": {
"provider": "string",
"model": "string",
"fallback": "strict",
"controls": "strict",
"options": {}
},
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"name": "My integration",
"speaker_version": 1,
"voice_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20"
}
],
"latest_project_exports": [
{
"schema_version": 1,
"id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"project_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"format": "mp3",
"status": "queued",
"percent": 1,
"created_at": "2026-09-30T17:00:00.000Z",
"sections": [
{
"section_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"title": "Chapter One",
"export_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"authority": {
"document_version": 1,
"speaker_registry_version": 1,
"mastering_version": 1
},
"export": {
"schema_version": 1,
"id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"project_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"section_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"format": "mp3",
"status": "queued",
"phase": "queued",
"percent": 1,
"cache_result": "miss",
"authority": {
"document_version": null,
"speaker_registry_version": null,
"mastering_version": null,
"is_current": null
},
"created_at": "2026-09-30T17:00:00.000Z",
"started_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"error": {
"code": null,
"message": null
},
"artifact": {
"asset_id": null,
"filename": null,
"content_type": null,
"size_bytes": null,
"download_url": null,
"download_url_expires_at": null,
"artifact_expires_at": null
}
},
"error": {
"code": "string",
"message": "string"
}
}
],
"archive": null
}
]
},
"request_id": "req_01J9Z3K8QF4"
}