---
title: "Workflows API"
description: "Workflows are durable, asynchronous jobs. A prepare workflow structures text into narration and dialogue; a Create Audio workflow casts voices and generates multi-voice audio. Poll a workflow until it reaches a terminal status."
canonical_url: https://lyricwinter.com/docs/api/workflows
markdown_url: https://lyricwinter.com/docs/api/workflows.md
last_updated: 2026-09-30
status: beta
---
# LyricWinter API reference: Workflows

> Workflows are durable, asynchronous jobs. A prepare workflow structures text into narration and dialogue; a Create Audio workflow casts voices and generates multi-voice audio. Poll a workflow until it reaches a terminal status.

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

- [Start a workflow](https://lyricwinter.com/docs/api/workflows#create-studio-workflow): `POST /studio/projects/{projectId}/workflows`
- [Get the latest project workflow](https://lyricwinter.com/docs/api/workflows#get-latest-studio-workflow): `GET /studio/projects/{projectId}/workflows`
- [Get a workflow](https://lyricwinter.com/docs/api/workflows#get-studio-workflow): `GET /studio/workflows/{workflowRunId}`
- [Get workflow audio progress](https://lyricwinter.com/docs/api/workflows#get-studio-workflow-progress): `GET /studio/workflows/{workflowRunId}/progress`
- [Cancel a workflow](https://lyricwinter.com/docs/api/workflows#cancel-studio-workflow): `POST /studio/workflows/{workflowRunId}/cancel`
- [Resume a failed workflow](https://lyricwinter.com/docs/api/workflows#resume-studio-workflow): `POST /studio/workflows/{workflowRunId}/resume`

### Start a workflow

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

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

Starts a `prepare_sections` workflow, which structures text into narration and dialogue, or a `create_audio` workflow, which prepares text, casts voices, directs performances, adds sound effects, and generates audio. Returns `202` with the run; poll it until it reaches a terminal status. Replaying the same `client_mutation_id` returns the same workflow instead of starting another.

#### Path parameters

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

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

- One of:
  - **schema_version: 1, workflow_kind: "prepare_sections"**: Start ordered section preparation.
    - `schema_version` (1; required)
    - `workflow_kind` ("prepare_sections"; required)
    - `actor_session_id` (string, uuid; required): Client session that issued the request.
    - `client_mutation_id` (string, uuid; required): Idempotency key; the workflow ID is derived from it. Reusing it for different content returns 409.
    - `section_ids` (array of string, 1–100 items, unique; required): Sections to prepare, in order; values must be unique.
  - **schema_version: 2, workflow_kind: "create_audio"**: Create Audio v2. Generated sound effects and automatic placement of linked project sounds are independent; when both run, project sounds are placed first. Section limit: 12 with both sound lanes enabled (the default), 14 with one, 16 with none. A target_scope requires exactly one section and both lanes set to false.
    - `schema_version` (2; required)
    - `workflow_kind` ("create_audio"; required)
    - `actor_session_id` (string, uuid; required): Client session that issued the request.
    - `client_mutation_id` (string, uuid; required): Idempotency key; the workflow ID is derived from it. Reusing it for different content returns 409.
    - `section_ids` (array of string, 1–16 items, unique; required): Sections to create audio for; values must be unique.
    - `include_generated_sfx` (boolean, default true; optional): Enables the generated-SFX authoring lane.
    - `place_project_sounds` (boolean, default true; optional): Enables automatic matching and placement from ready, accessible sounds explicitly linked to this project.
    - `direct_emotion` (boolean, default true; optional): Enables automatic emotion: a direct_emotion step adds provider delivery directions to spoken blocks that have none for their engine. Direction text sent to the provider is billed (ElevenLabs v4 audio tags). For pre-run estimates, clients add about 18 ElevenLabs v4 tokens per untagged ElevenLabs v4 block while this is on; the charge is the tokens actually sent. Omitted means true.
    - `target_scope` (object | null; optional): Optional focused source-block scope. Null or omitted targets the selected sections. Focused requests must set both optional sound lanes to false.
      - `kind` ("source_blocks"; required)
      - `blocks` (array of object, 1–250 items, unique; required): Focused source blocks; block_id values must be unique.
        - `block_id` (string, uuid; required)
        - `base_block_version` (integer, ≥ 1; required)
        - `text_length_utf16` (integer, 1–1000000; required)
        - `text_hash` (string, pattern ^[0-9a-f]{64}$; required)

#### Response 202

Durable project workflow accepted and first advancement attempted. Replaying the same client_mutation_id with the same request returns the same workflow.

Fields inside `data`:

- `run` (object; required): Durable Studio project workflow run.
  - `id` (string, uuid; required): Workflow run ID.
  - `project_id` (string, uuid; required)
  - `requested_by_user_id` (string, uuid; required)
  - `payer_user_id` (string | null, uuid; required): User billed for Create Audio work; null for prepare_sections workflows.
  - `workflow_kind` (string, one of `prepare_sections`, `create_audio`; required)
  - `automation_profile` (string | null, one of `quick`, `balanced`, `directed`; required): Create Audio profile label from profile_snapshot.profile; null for prepare_sections.
  - `profile_snapshot` (object; required): Empty object for prepare_sections workflows; the frozen Create Audio options for create_audio workflows.
  - `status` (string, one of `queued`, `running`, `completed`, `partially_completed`, `failed`, `canceling`, `cancelled`; required): Workflow run status, recomputed from step statuses after every step transition. Non-terminal: queued (unfinished steps remain and none is active), running (at least one step is active), canceling (cancellation was requested and unfinished steps remain). Terminal (completed_at is set and the status no longer changes): completed (every step succeeded or was skipped), partially_completed (at least one failed or conflict step and at least one succeeded or skipped step), failed (failed or conflict steps and no succeeded or skipped step), cancelled (all steps finished after cancellation was requested).
  - `current_stage` (string | null, one of `preparing_sections`, `assigning_speakers`, `casting_voices`, `planning_emotion`, `directing_delivery`, `placing_project_sounds`, `directing_sfx`, `preparing_voices`, `generating_audio`; required): Stage of the next unfinished step while the run is queued, running, or canceling. Null once the run is terminal, or when the next unfinished step is render_section.
  - `step_count` (integer, 1–100; required)
  - `completed_step_count` (integer, 0–100; required): Steps in a terminal status (succeeded, skipped, failed, conflict, cancelled).
  - `progress` (object; required): Step counts by status. Currently contains integer counts pending, active, succeeded (succeeded or skipped), failed (failed or conflict), cancelled, completed (all terminal), and total; treat unknown keys as additive.
    - `pending` (integer, ≥ 0; optional)
    - `active` (integer, ≥ 0; optional)
    - `succeeded` (integer, ≥ 0; optional)
    - `failed` (integer, ≥ 0; optional)
    - `cancelled` (integer, ≥ 0; optional)
    - `completed` (integer, ≥ 0; optional)
    - `total` (integer, ≥ 0; optional)
  - `error_summary` (array of object, max 100 items; required): One entry per failed or conflict step in step order. Entries currently contain step_id, section_id, step_kind, code, and message; treat unknown keys as additive.
    - `step_id` (string, uuid; optional)
    - `section_id` (string, uuid; optional)
    - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; optional): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
    - `code` (string | null; optional)
    - `message` (string | null; optional)
  - `cancel_requested_at` (string | null, date-time; required): When cancellation was first requested.
  - `cancel_acknowledged_at` (string | null, date-time; required): When the run reached cancelled.
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required): When execution first started; null before then.
  - `completed_at` (string | null, date-time; required): Set when the run reaches a terminal status (completed, partially_completed, failed, cancelled); null otherwise.
  - `resumes_workflow_run_id` (string | null, uuid; required): Predecessor run this run resumes; null for an original run.
  - `resumable` (boolean; required): True when status is failed or partially_completed and at least one step is failed or conflict. Only resumable runs can be resumed.
- `steps` (array of object, 1–100 items; required): All steps in ascending step_index order.
  - `id` (string, uuid; required)
  - `workflow_run_id` (string, uuid; required)
  - `section_id` (string, uuid; required)
  - `step_key` (string, 1–200 chars; required): Stable key of the step within its workflow.
  - `step_index` (integer, 0–99; required): Zero-based position; steps are returned in ascending step_index order.
  - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; required): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
  - `status` (string, one of `pending`, `active`, `succeeded`, `skipped`, `failed`, `conflict`, `cancelled`; required): Step status. pending and active are non-terminal; succeeded, skipped, failed, conflict, and cancelled are terminal. The run counts skipped as success and conflict as failure. conflict means the section document changed underneath the step.
  - `requested_document_version` (integer, ≥ 1; required): Section document version the step was planned against.
  - `execution_document_version` (integer | null, ≥ 1; required): Section document version the step executed against, when recorded.
  - `assistant_batch_id` (string | null, uuid; required): Child assistant batch started by an assistant-driven step.
  - `render_run_id` (string | null, uuid; required): Render run started by a render_section step.
  - `result_summary` (object; required): Step-specific result data, typed by the contract as an open JSON object. generate_stale_audio steps may carry the StudioWorkflowAudioResultSummary fields; steps cancelled before starting carry cancelled_before_start: true.
  - `issue_kind` (string | null, one of `document_changed`, `service_out_of_sync`, `assistant_failed`, `workflow_failed`; required): Set for failed and conflict steps; null for every other status.
  - `error_code` (string | null, 1–200 chars; required)
  - `error_message` (string | null, max 10000 chars; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required)
  - `completed_at` (string | null, date-time; required)

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

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/workflows" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "schema_version": 1,
  "workflow_kind": "prepare_sections",
  "actor_session_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
  "client_mutation_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
  "section_ids": [
    "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30"
  ]
}'
```

### Get the latest project workflow

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

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

Returns the project's most recent workflow with its steps, or `null` if none has run. Pass `section_id` to get the most recent workflow that includes that section.

#### Path parameters

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

#### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `section_id` | string, uuid | No | Restrict to the workflow that most recently added a step for this section. Returns null when none exists or that workflow belongs to another project. |

#### Response 200

Latest project workflow or null when none exists.

Fields inside `data`:

- `run` (object; required): Durable Studio project workflow run.
  - `id` (string, uuid; required): Workflow run ID.
  - `project_id` (string, uuid; required)
  - `requested_by_user_id` (string, uuid; required)
  - `payer_user_id` (string | null, uuid; required): User billed for Create Audio work; null for prepare_sections workflows.
  - `workflow_kind` (string, one of `prepare_sections`, `create_audio`; required)
  - `automation_profile` (string | null, one of `quick`, `balanced`, `directed`; required): Create Audio profile label from profile_snapshot.profile; null for prepare_sections.
  - `profile_snapshot` (object; required): Empty object for prepare_sections workflows; the frozen Create Audio options for create_audio workflows.
  - `status` (string, one of `queued`, `running`, `completed`, `partially_completed`, `failed`, `canceling`, `cancelled`; required): Workflow run status, recomputed from step statuses after every step transition. Non-terminal: queued (unfinished steps remain and none is active), running (at least one step is active), canceling (cancellation was requested and unfinished steps remain). Terminal (completed_at is set and the status no longer changes): completed (every step succeeded or was skipped), partially_completed (at least one failed or conflict step and at least one succeeded or skipped step), failed (failed or conflict steps and no succeeded or skipped step), cancelled (all steps finished after cancellation was requested).
  - `current_stage` (string | null, one of `preparing_sections`, `assigning_speakers`, `casting_voices`, `planning_emotion`, `directing_delivery`, `placing_project_sounds`, `directing_sfx`, `preparing_voices`, `generating_audio`; required): Stage of the next unfinished step while the run is queued, running, or canceling. Null once the run is terminal, or when the next unfinished step is render_section.
  - `step_count` (integer, 1–100; required)
  - `completed_step_count` (integer, 0–100; required): Steps in a terminal status (succeeded, skipped, failed, conflict, cancelled).
  - `progress` (object; required): Step counts by status. Currently contains integer counts pending, active, succeeded (succeeded or skipped), failed (failed or conflict), cancelled, completed (all terminal), and total; treat unknown keys as additive.
    - `pending` (integer, ≥ 0; optional)
    - `active` (integer, ≥ 0; optional)
    - `succeeded` (integer, ≥ 0; optional)
    - `failed` (integer, ≥ 0; optional)
    - `cancelled` (integer, ≥ 0; optional)
    - `completed` (integer, ≥ 0; optional)
    - `total` (integer, ≥ 0; optional)
  - `error_summary` (array of object, max 100 items; required): One entry per failed or conflict step in step order. Entries currently contain step_id, section_id, step_kind, code, and message; treat unknown keys as additive.
    - `step_id` (string, uuid; optional)
    - `section_id` (string, uuid; optional)
    - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; optional): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
    - `code` (string | null; optional)
    - `message` (string | null; optional)
  - `cancel_requested_at` (string | null, date-time; required): When cancellation was first requested.
  - `cancel_acknowledged_at` (string | null, date-time; required): When the run reached cancelled.
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required): When execution first started; null before then.
  - `completed_at` (string | null, date-time; required): Set when the run reaches a terminal status (completed, partially_completed, failed, cancelled); null otherwise.
  - `resumes_workflow_run_id` (string | null, uuid; required): Predecessor run this run resumes; null for an original run.
  - `resumable` (boolean; required): True when status is failed or partially_completed and at least one step is failed or conflict. Only resumable runs can be resumed.
- `steps` (array of object, 1–100 items; required): All steps in ascending step_index order.
  - `id` (string, uuid; required)
  - `workflow_run_id` (string, uuid; required)
  - `section_id` (string, uuid; required)
  - `step_key` (string, 1–200 chars; required): Stable key of the step within its workflow.
  - `step_index` (integer, 0–99; required): Zero-based position; steps are returned in ascending step_index order.
  - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; required): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
  - `status` (string, one of `pending`, `active`, `succeeded`, `skipped`, `failed`, `conflict`, `cancelled`; required): Step status. pending and active are non-terminal; succeeded, skipped, failed, conflict, and cancelled are terminal. The run counts skipped as success and conflict as failure. conflict means the section document changed underneath the step.
  - `requested_document_version` (integer, ≥ 1; required): Section document version the step was planned against.
  - `execution_document_version` (integer | null, ≥ 1; required): Section document version the step executed against, when recorded.
  - `assistant_batch_id` (string | null, uuid; required): Child assistant batch started by an assistant-driven step.
  - `render_run_id` (string | null, uuid; required): Render run started by a render_section step.
  - `result_summary` (object; required): Step-specific result data, typed by the contract as an open JSON object. generate_stale_audio steps may carry the StudioWorkflowAudioResultSummary fields; steps cancelled before starting carry cancelled_before_start: true.
  - `issue_kind` (string | null, one of `document_changed`, `service_out_of_sync`, `assistant_failed`, `workflow_failed`; required): Set for failed and conflict steps; null for every other status.
  - `error_code` (string | null, 1–200 chars; required)
  - `error_message` (string | null, max 10000 chars; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required)
  - `completed_at` (string | null, date-time; required)

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

#### Example request

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

### Get a workflow

`GET /studio/workflows/{workflowRunId}`

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

Returns a workflow run and its ordered steps. Poll this endpoint until `run.status` is `completed`, `partially_completed`, `failed`, or `cancelled`.

#### Path parameters

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

#### Response 200

Current workflow and ordered section steps. Poll until run.status is terminal (completed, partially_completed, failed, cancelled).

Fields inside `data`:

- `run` (object; required): Durable Studio project workflow run.
  - `id` (string, uuid; required): Workflow run ID.
  - `project_id` (string, uuid; required)
  - `requested_by_user_id` (string, uuid; required)
  - `payer_user_id` (string | null, uuid; required): User billed for Create Audio work; null for prepare_sections workflows.
  - `workflow_kind` (string, one of `prepare_sections`, `create_audio`; required)
  - `automation_profile` (string | null, one of `quick`, `balanced`, `directed`; required): Create Audio profile label from profile_snapshot.profile; null for prepare_sections.
  - `profile_snapshot` (object; required): Empty object for prepare_sections workflows; the frozen Create Audio options for create_audio workflows.
  - `status` (string, one of `queued`, `running`, `completed`, `partially_completed`, `failed`, `canceling`, `cancelled`; required): Workflow run status, recomputed from step statuses after every step transition. Non-terminal: queued (unfinished steps remain and none is active), running (at least one step is active), canceling (cancellation was requested and unfinished steps remain). Terminal (completed_at is set and the status no longer changes): completed (every step succeeded or was skipped), partially_completed (at least one failed or conflict step and at least one succeeded or skipped step), failed (failed or conflict steps and no succeeded or skipped step), cancelled (all steps finished after cancellation was requested).
  - `current_stage` (string | null, one of `preparing_sections`, `assigning_speakers`, `casting_voices`, `planning_emotion`, `directing_delivery`, `placing_project_sounds`, `directing_sfx`, `preparing_voices`, `generating_audio`; required): Stage of the next unfinished step while the run is queued, running, or canceling. Null once the run is terminal, or when the next unfinished step is render_section.
  - `step_count` (integer, 1–100; required)
  - `completed_step_count` (integer, 0–100; required): Steps in a terminal status (succeeded, skipped, failed, conflict, cancelled).
  - `progress` (object; required): Step counts by status. Currently contains integer counts pending, active, succeeded (succeeded or skipped), failed (failed or conflict), cancelled, completed (all terminal), and total; treat unknown keys as additive.
    - `pending` (integer, ≥ 0; optional)
    - `active` (integer, ≥ 0; optional)
    - `succeeded` (integer, ≥ 0; optional)
    - `failed` (integer, ≥ 0; optional)
    - `cancelled` (integer, ≥ 0; optional)
    - `completed` (integer, ≥ 0; optional)
    - `total` (integer, ≥ 0; optional)
  - `error_summary` (array of object, max 100 items; required): One entry per failed or conflict step in step order. Entries currently contain step_id, section_id, step_kind, code, and message; treat unknown keys as additive.
    - `step_id` (string, uuid; optional)
    - `section_id` (string, uuid; optional)
    - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; optional): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
    - `code` (string | null; optional)
    - `message` (string | null; optional)
  - `cancel_requested_at` (string | null, date-time; required): When cancellation was first requested.
  - `cancel_acknowledged_at` (string | null, date-time; required): When the run reached cancelled.
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required): When execution first started; null before then.
  - `completed_at` (string | null, date-time; required): Set when the run reaches a terminal status (completed, partially_completed, failed, cancelled); null otherwise.
  - `resumes_workflow_run_id` (string | null, uuid; required): Predecessor run this run resumes; null for an original run.
  - `resumable` (boolean; required): True when status is failed or partially_completed and at least one step is failed or conflict. Only resumable runs can be resumed.
- `steps` (array of object, 1–100 items; required): All steps in ascending step_index order.
  - `id` (string, uuid; required)
  - `workflow_run_id` (string, uuid; required)
  - `section_id` (string, uuid; required)
  - `step_key` (string, 1–200 chars; required): Stable key of the step within its workflow.
  - `step_index` (integer, 0–99; required): Zero-based position; steps are returned in ascending step_index order.
  - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; required): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
  - `status` (string, one of `pending`, `active`, `succeeded`, `skipped`, `failed`, `conflict`, `cancelled`; required): Step status. pending and active are non-terminal; succeeded, skipped, failed, conflict, and cancelled are terminal. The run counts skipped as success and conflict as failure. conflict means the section document changed underneath the step.
  - `requested_document_version` (integer, ≥ 1; required): Section document version the step was planned against.
  - `execution_document_version` (integer | null, ≥ 1; required): Section document version the step executed against, when recorded.
  - `assistant_batch_id` (string | null, uuid; required): Child assistant batch started by an assistant-driven step.
  - `render_run_id` (string | null, uuid; required): Render run started by a render_section step.
  - `result_summary` (object; required): Step-specific result data, typed by the contract as an open JSON object. generate_stale_audio steps may carry the StudioWorkflowAudioResultSummary fields; steps cancelled before starting carry cancelled_before_start: true.
  - `issue_kind` (string | null, one of `document_changed`, `service_out_of_sync`, `assistant_failed`, `workflow_failed`; required): Set for failed and conflict steps; null for every other status.
  - `error_code` (string | null, 1–200 chars; required)
  - `error_message` (string | null, max 10000 chars; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required)
  - `completed_at` (string | null, date-time; required)

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

#### Example request

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

### Get workflow audio progress

`GET /studio/workflows/{workflowRunId}/progress`

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

Returns how many audio clips are ready out of the total for a Create Audio workflow. Use it for a progress bar while audio generates.

#### Path parameters

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

#### Response 200

Current workflow audio counts.

Fields inside `data`:

- `schema_version` (integer, one of `1`; required)
- `workflow_run_id` (string, uuid; required)
- `ready` (integer, ≥ 0; required)
- `total` (integer, ≥ 0; required)

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

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/studio/workflows/$WORKFLOW_RUN_ID/progress" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Cancel a workflow

`POST /studio/workflows/{workflowRunId}/cancel`

Scope: `studio:write` · Operation ID: `cancelStudioWorkflow`

Requests cancellation of a prepare or Create Audio workflow. Pending steps are cancelled immediately; running steps stop cooperatively and their late results are discarded. A finished workflow is returned unchanged. Send no request body.

#### Path parameters

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

#### Response 200

Current workflow state, normally canceling or cancelled.

Fields inside `data`:

- `run` (object; required): Durable Studio project workflow run.
  - `id` (string, uuid; required): Workflow run ID.
  - `project_id` (string, uuid; required)
  - `requested_by_user_id` (string, uuid; required)
  - `payer_user_id` (string | null, uuid; required): User billed for Create Audio work; null for prepare_sections workflows.
  - `workflow_kind` (string, one of `prepare_sections`, `create_audio`; required)
  - `automation_profile` (string | null, one of `quick`, `balanced`, `directed`; required): Create Audio profile label from profile_snapshot.profile; null for prepare_sections.
  - `profile_snapshot` (object; required): Empty object for prepare_sections workflows; the frozen Create Audio options for create_audio workflows.
  - `status` (string, one of `queued`, `running`, `completed`, `partially_completed`, `failed`, `canceling`, `cancelled`; required): Workflow run status, recomputed from step statuses after every step transition. Non-terminal: queued (unfinished steps remain and none is active), running (at least one step is active), canceling (cancellation was requested and unfinished steps remain). Terminal (completed_at is set and the status no longer changes): completed (every step succeeded or was skipped), partially_completed (at least one failed or conflict step and at least one succeeded or skipped step), failed (failed or conflict steps and no succeeded or skipped step), cancelled (all steps finished after cancellation was requested).
  - `current_stage` (string | null, one of `preparing_sections`, `assigning_speakers`, `casting_voices`, `planning_emotion`, `directing_delivery`, `placing_project_sounds`, `directing_sfx`, `preparing_voices`, `generating_audio`; required): Stage of the next unfinished step while the run is queued, running, or canceling. Null once the run is terminal, or when the next unfinished step is render_section.
  - `step_count` (integer, 1–100; required)
  - `completed_step_count` (integer, 0–100; required): Steps in a terminal status (succeeded, skipped, failed, conflict, cancelled).
  - `progress` (object; required): Step counts by status. Currently contains integer counts pending, active, succeeded (succeeded or skipped), failed (failed or conflict), cancelled, completed (all terminal), and total; treat unknown keys as additive.
    - `pending` (integer, ≥ 0; optional)
    - `active` (integer, ≥ 0; optional)
    - `succeeded` (integer, ≥ 0; optional)
    - `failed` (integer, ≥ 0; optional)
    - `cancelled` (integer, ≥ 0; optional)
    - `completed` (integer, ≥ 0; optional)
    - `total` (integer, ≥ 0; optional)
  - `error_summary` (array of object, max 100 items; required): One entry per failed or conflict step in step order. Entries currently contain step_id, section_id, step_kind, code, and message; treat unknown keys as additive.
    - `step_id` (string, uuid; optional)
    - `section_id` (string, uuid; optional)
    - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; optional): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
    - `code` (string | null; optional)
    - `message` (string | null; optional)
  - `cancel_requested_at` (string | null, date-time; required): When cancellation was first requested.
  - `cancel_acknowledged_at` (string | null, date-time; required): When the run reached cancelled.
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required): When execution first started; null before then.
  - `completed_at` (string | null, date-time; required): Set when the run reaches a terminal status (completed, partially_completed, failed, cancelled); null otherwise.
  - `resumes_workflow_run_id` (string | null, uuid; required): Predecessor run this run resumes; null for an original run.
  - `resumable` (boolean; required): True when status is failed or partially_completed and at least one step is failed or conflict. Only resumable runs can be resumed.
- `steps` (array of object, 1–100 items; required): All steps in ascending step_index order.
  - `id` (string, uuid; required)
  - `workflow_run_id` (string, uuid; required)
  - `section_id` (string, uuid; required)
  - `step_key` (string, 1–200 chars; required): Stable key of the step within its workflow.
  - `step_index` (integer, 0–99; required): Zero-based position; steps are returned in ascending step_index order.
  - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; required): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
  - `status` (string, one of `pending`, `active`, `succeeded`, `skipped`, `failed`, `conflict`, `cancelled`; required): Step status. pending and active are non-terminal; succeeded, skipped, failed, conflict, and cancelled are terminal. The run counts skipped as success and conflict as failure. conflict means the section document changed underneath the step.
  - `requested_document_version` (integer, ≥ 1; required): Section document version the step was planned against.
  - `execution_document_version` (integer | null, ≥ 1; required): Section document version the step executed against, when recorded.
  - `assistant_batch_id` (string | null, uuid; required): Child assistant batch started by an assistant-driven step.
  - `render_run_id` (string | null, uuid; required): Render run started by a render_section step.
  - `result_summary` (object; required): Step-specific result data, typed by the contract as an open JSON object. generate_stale_audio steps may carry the StudioWorkflowAudioResultSummary fields; steps cancelled before starting carry cancelled_before_start: true.
  - `issue_kind` (string | null, one of `document_changed`, `service_out_of_sync`, `assistant_failed`, `workflow_failed`; required): Set for failed and conflict steps; null for every other status.
  - `error_code` (string | null, 1–200 chars; required)
  - `error_message` (string | null, max 10000 chars; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required)
  - `completed_at` (string | null, date-time; required)

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

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/studio/workflows/$WORKFLOW_RUN_ID/cancel" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Resume a failed workflow

`POST /studio/workflows/{workflowRunId}/resume`

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

Starts a new workflow linked to a failed or partially completed run. It picks up from each section's first failed stage instead of redoing finished work. Only runs with `resumable: true` can be resumed.

#### Path parameters

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

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

- `schema_version` (1; required)
- `actor_session_id` (string, uuid; required): Client session that issued the request.
- `client_mutation_id` (string, uuid; required): Idempotency key; the successor workflow ID is derived from it. Reusing it for different content returns 409.

#### Response 202

The linked successor workflow and its recovery steps.

Fields inside `data`:

- `run` (object; required): Durable Studio project workflow run.
  - `id` (string, uuid; required): Workflow run ID.
  - `project_id` (string, uuid; required)
  - `requested_by_user_id` (string, uuid; required)
  - `payer_user_id` (string | null, uuid; required): User billed for Create Audio work; null for prepare_sections workflows.
  - `workflow_kind` (string, one of `prepare_sections`, `create_audio`; required)
  - `automation_profile` (string | null, one of `quick`, `balanced`, `directed`; required): Create Audio profile label from profile_snapshot.profile; null for prepare_sections.
  - `profile_snapshot` (object; required): Empty object for prepare_sections workflows; the frozen Create Audio options for create_audio workflows.
  - `status` (string, one of `queued`, `running`, `completed`, `partially_completed`, `failed`, `canceling`, `cancelled`; required): Workflow run status, recomputed from step statuses after every step transition. Non-terminal: queued (unfinished steps remain and none is active), running (at least one step is active), canceling (cancellation was requested and unfinished steps remain). Terminal (completed_at is set and the status no longer changes): completed (every step succeeded or was skipped), partially_completed (at least one failed or conflict step and at least one succeeded or skipped step), failed (failed or conflict steps and no succeeded or skipped step), cancelled (all steps finished after cancellation was requested).
  - `current_stage` (string | null, one of `preparing_sections`, `assigning_speakers`, `casting_voices`, `planning_emotion`, `directing_delivery`, `placing_project_sounds`, `directing_sfx`, `preparing_voices`, `generating_audio`; required): Stage of the next unfinished step while the run is queued, running, or canceling. Null once the run is terminal, or when the next unfinished step is render_section.
  - `step_count` (integer, 1–100; required)
  - `completed_step_count` (integer, 0–100; required): Steps in a terminal status (succeeded, skipped, failed, conflict, cancelled).
  - `progress` (object; required): Step counts by status. Currently contains integer counts pending, active, succeeded (succeeded or skipped), failed (failed or conflict), cancelled, completed (all terminal), and total; treat unknown keys as additive.
    - `pending` (integer, ≥ 0; optional)
    - `active` (integer, ≥ 0; optional)
    - `succeeded` (integer, ≥ 0; optional)
    - `failed` (integer, ≥ 0; optional)
    - `cancelled` (integer, ≥ 0; optional)
    - `completed` (integer, ≥ 0; optional)
    - `total` (integer, ≥ 0; optional)
  - `error_summary` (array of object, max 100 items; required): One entry per failed or conflict step in step order. Entries currently contain step_id, section_id, step_kind, code, and message; treat unknown keys as additive.
    - `step_id` (string, uuid; optional)
    - `section_id` (string, uuid; optional)
    - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; optional): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
    - `code` (string | null; optional)
    - `message` (string | null; optional)
  - `cancel_requested_at` (string | null, date-time; required): When cancellation was first requested.
  - `cancel_acknowledged_at` (string | null, date-time; required): When the run reached cancelled.
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required): When execution first started; null before then.
  - `completed_at` (string | null, date-time; required): Set when the run reaches a terminal status (completed, partially_completed, failed, cancelled); null otherwise.
  - `resumes_workflow_run_id` (string | null, uuid; required): Predecessor run this run resumes; null for an original run.
  - `resumable` (boolean; required): True when status is failed or partially_completed and at least one step is failed or conflict. Only resumable runs can be resumed.
- `steps` (array of object, 1–100 items; required): All steps in ascending step_index order.
  - `id` (string, uuid; required)
  - `workflow_run_id` (string, uuid; required)
  - `section_id` (string, uuid; required)
  - `step_key` (string, 1–200 chars; required): Stable key of the step within its workflow.
  - `step_index` (integer, 0–99; required): Zero-based position; steps are returned in ascending step_index order.
  - `step_kind` (string, one of `prepare_section`, `assign_speakers`, `cast_voices`, `direct_emotion`, `direct_section_delivery`, `place_project_sounds`, `direct_sfx`, `prepare_voices`, `generate_stale_audio`, `render_section`; required): Kind of work a step performs. prepare_sections workflows contain only prepare_section steps. direct_section_delivery and render_section come from older Create Audio profiles (and successors resumed from them); new workflows do not plan them.
  - `status` (string, one of `pending`, `active`, `succeeded`, `skipped`, `failed`, `conflict`, `cancelled`; required): Step status. pending and active are non-terminal; succeeded, skipped, failed, conflict, and cancelled are terminal. The run counts skipped as success and conflict as failure. conflict means the section document changed underneath the step.
  - `requested_document_version` (integer, ≥ 1; required): Section document version the step was planned against.
  - `execution_document_version` (integer | null, ≥ 1; required): Section document version the step executed against, when recorded.
  - `assistant_batch_id` (string | null, uuid; required): Child assistant batch started by an assistant-driven step.
  - `render_run_id` (string | null, uuid; required): Render run started by a render_section step.
  - `result_summary` (object; required): Step-specific result data, typed by the contract as an open JSON object. generate_stale_audio steps may carry the StudioWorkflowAudioResultSummary fields; steps cancelled before starting carry cancelled_before_start: true.
  - `issue_kind` (string | null, one of `document_changed`, `service_out_of_sync`, `assistant_failed`, `workflow_failed`; required): Set for failed and conflict steps; null for every other status.
  - `error_code` (string | null, 1–200 chars; required)
  - `error_message` (string | null, max 10000 chars; required)
  - `created_at` (string, date-time; required)
  - `updated_at` (string, date-time; required)
  - `started_at` (string | null, date-time; required)
  - `completed_at` (string | null, date-time; required)

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

#### Example request

```bash
curl -X POST "https://lyricwinter.com/api/v1/studio/workflows/$WORKFLOW_RUN_ID/resume" \
  -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"
}'
```

