---
title: "Media and playback API"
description: "Read the generated audio state for a section, compile a playback manifest for the current document version, and mint short-lived URLs for individual media assets."
canonical_url: https://lyricwinter.com/docs/api/media
markdown_url: https://lyricwinter.com/docs/api/media.md
last_updated: 2026-09-30
status: beta
---
# LyricWinter API reference: Media and playback

> Read the generated audio state for a section, compile a playback manifest for the current document version, and mint short-lived URLs for individual media assets.

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

## Endpoints

- [Get section media](https://lyricwinter.com/docs/api/media#get-studio-section-media): `GET /studio/sections/{sectionId}/media`
- [Get a playback manifest](https://lyricwinter.com/docs/api/media#get-studio-playback-manifest): `GET /studio/sections/{sectionId}/playback-manifest`
- [Create a media access URL](https://lyricwinter.com/docs/api/media#create-studio-media-access-url): `POST /studio/media-assets/{assetId}/access-url`

### Get section media

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

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

Returns one entry per document block with its audio `freshness`, generation `activity`, and a short-lived signed `playback_url` for the current audio, plus the section's playback duration.

#### Path parameters

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

#### Response 200

Current block media read model.

Fields inside `data`:

- `section_id` (string, uuid; required)
- `playback_duration_ms` (integer | null, ≥ 0; required): Duration of the newest saved render manifest for the section's current document and speaker-registry versions; null when none exists.
- `blocks` (array of object; required): One entry per document block, in document order.
  - `block_id` (string, uuid; required)
  - `freshness` (string, one of `absent`, `current`, `stale`, `unsupported`; required): absent: 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.
  - `activity` (string, one of `idle`, `generating`, `failed`; required): generating: 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.
  - `active_block_version` (integer | null, ≥ 1; required): Block version the active rendition was requested for.
  - `requested_block_version` (integer | null, ≥ 1; required): Block version of the pending rendition or import, if any.
  - `active_rendition_id` (string | null, uuid; required)
  - `audio_version_count` (integer, ≥ 0; required): Number of completed audio versions for the block.
  - `generation_batch_id` (string | null, uuid; required): Generation batch of the pending rendition.
  - `playback_url` (string | null, uri; required): Short-lived signed URL for the active rendition's audio; null without an active asset.
  - `playback_url_expires_at` (string | null, date-time; required)
  - `content_type` (string | null; required)
  - `size_bytes` (integer | null, ≥ 1; required)
  - `analysis_integrated_lufs` (number | null, -120–24; required)
  - `analysis_sample_peak_dbfs` (number | null, -200–24; required)
  - `provider` (string | null; required): Provider that actually produced the active rendition (stored metadata for imports).
  - `model` (string | null; required): Model that actually produced the active rendition (stored metadata for imports).
  - `error` (string | null; required): Latest generation or import error message.
  - `stale_reasons` (array of string, one of `block_kind`, `text`, `pronunciation`, `excluded_text`, `timing`, `voice`, `generation_profile`, `delivery_controls`, `sound_effect`; optional): Present for speech, narration, and sfx blocks; non-empty only when freshness is stale.

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

#### Example request

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

### Get a playback manifest

`GET /studio/sections/{sectionId}/playback-manifest`

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

Compiles the section's current speech, pauses, and sound-effect overlays into one timeline with signed asset URLs for gapless playback. Pass the `document_version` and `speaker_registry_version` from the document; any other query parameter returns `400`.

#### Path parameters

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

#### Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `document_version` | integer, ≥ 1 | Yes | Saved section document version to compile. If it no longer matches the saved section, the request fails with 409 STUDIO_PLAYBACK_STALE. |
| `speaker_registry_version` | integer, ≥ 1 | Yes | Saved speaker-registry (cast) version to compile. If it no longer matches, the request fails with 409 STUDIO_PLAYBACK_STALE. |

#### Response 200

Current private playback manifest and signed asset URLs.

Fields inside `data`:

- `schema_version` (1; required)
- `mastering_version` (integer, ≥ 1; required)
- `manifest_hash` (string, pattern ^[a-f0-9]{64}$; required): SHA-256 of the canonical manifest.
- `manifest` (object; required): Compiled playback timeline for one saved section document and speaker-registry version.
  - `schema_version` ("studio-render-manifest-2"; required)
  - `project_id` (string, uuid; required)
  - `section_id` (string, uuid; required)
  - `document_version` (integer, ≥ 1; required)
  - `speaker_registry_version` (integer, ≥ 1; required)
  - `mastering_version` (integer, ≥ 1; required)
  - `mastering_profile_hash` (string, pattern ^[a-f0-9]{64}$; required)
  - `mastering_profile` (object; required)
    - `schema_version` (1; required)
    - `enabled` (boolean; required)
    - `target_lufs` (number, -30–-10; required)
    - `strength` (number, 0–1; required)
    - `max_boost_db` (number, 0–24; required)
    - `max_reduction_db` (number, 0–24; required)
    - `silence_threshold_lufs` (number, -120–-20; required)
    - `peak_ceiling_db` (number, -12–-0.1; required)
    - `speaker_adjustments_db` (map of number; required)
    - `sfx_bus_gain_db` (number, -24–24, default 0; required)
  - `completeness` (string, one of `partial`, `complete`; required): complete exactly when gaps is empty.
  - `duration_ms` (integer, ≥ 0; required): Latest end point of any sequential or overlay unit.
  - `sequential_units` (array of object, max 50000 items; required): Contiguous from 0 ms in canonical block order; unit IDs are unique across sequential and overlay units.
    - One of:
      - **unit_type: "asset"**
        - `unit_id` (string, uuid; required)
        - `block_id` (string, uuid; required)
        - `block_index` (integer, ≥ 0; required)
        - `block_version` (integer, ≥ 1; required)
        - `block_kind` (string, one of `speech`, `narration`; required)
        - `start_ms` (integer, ≥ 0; required)
        - `duration_ms` (integer, ≥ 1; required)
        - `rendition_id` (string, uuid; required)
        - `rendition_intent_hash` (string, pattern ^[a-f0-9]{64}$; required)
        - `unit_type` ("asset"; required)
        - `asset_id` (string, uuid; required): Key into the payload's assets array.
        - `asset_content_hash` (string, pattern ^[a-f0-9]{64}$; required)
        - `source_ranges` (array of object, 1–10000 items; required)
          - `start_utf16` (integer, ≥ 0; required)
          - `end_utf16` (integer, ≥ 0; required)
        - `speaker_id` (string, uuid; required)
        - `analysis_integrated_lufs` (number, -120–12; required)
        - `analysis_sample_peak_dbfs` (number, -200–12; required)
        - `effective_gain_db` (number, -24–24; required)
      - **unit_type: "silence"**
        - `unit_id` (string, uuid; required)
        - `block_id` (string, uuid; required)
        - `block_index` (integer, ≥ 0; required)
        - `block_version` (integer, ≥ 1; required)
        - `block_kind` (string, one of `speech`, `narration`; required)
        - `start_ms` (integer, ≥ 0; required)
        - `duration_ms` (integer, ≥ 1; required)
        - `rendition_id` (string, uuid; required)
        - `rendition_intent_hash` (string, pattern ^[a-f0-9]{64}$; required)
        - `unit_type` ("silence"; required)
      - **unit_type: "spacing", spacing_kind: "inter_passage"**
        - `unit_id` (string, uuid; required)
        - `block_id` (string, uuid; required)
        - `block_index` (integer, ≥ 0; required)
        - `block_version` (integer, ≥ 1; required)
        - `block_kind` (string, one of `speech`, `narration`; required)
        - `start_ms` (integer, ≥ 0; required)
        - `duration_ms` (integer, ≥ 1; required)
        - `unit_type` ("spacing"; required)
        - `spacing_kind` ("inter_passage"; required)
  - `overlay_units` (array of object, max 10000 items; required): Ordered by start_ms, block_index, block_id, unit_id.
    - `unit_type` ("sfx"; required)
    - `unit_id` (string, uuid; required)
    - `block_id` (string, uuid; required)
    - `block_index` (integer, ≥ 0; required)
    - `block_version` (integer, ≥ 1; required)
    - `intent_hash` (string, pattern ^[a-f0-9]{64}$; required)
    - `asset_id` (string, uuid; required): Key into the payload's assets array.
    - `asset_content_hash` (string, pattern ^[a-f0-9]{64}$; required)
    - `start_ms` (integer, ≥ 0; required)
    - `duration_ms` (integer, ≥ 1; required)
    - `gain_db` (number, -60–24; required)
    - `fade_in_ms` (integer, ≥ 0; required)
    - `fade_out_ms` (integer, ≥ 0; required)
  - `timed_text_units` (array of object, max 50000 items; required): Ordered by start_ms, block_index, block_id, unit_id.
    - `unit_id` (string, uuid; required)
    - `block_id` (string, uuid; required)
    - `block_index` (integer, ≥ 0; required)
    - `block_version` (integer, ≥ 1; required)
    - `speaker_id` (string, uuid; required)
    - `start_ms` (integer, ≥ 0; required)
    - `duration_ms` (integer, ≥ 1; required)
    - `text` (string, 1–100000 chars; required)
    - `text_hash` (string, pattern ^[a-f0-9]{64}$; required)
    - `source_ranges` (array of object, 1–10000 items; required)
      - `start_utf16` (integer, ≥ 0; required)
      - `end_utf16` (integer, ≥ 0; required)
  - `gaps` (array of object, max 50000 items; required): Ordered by block_index, media_kind, block_id.
    - One of:
      - **media_kind: "speech"**
        - `block_id` (string, uuid; required)
        - `block_index` (integer, ≥ 0; required)
        - `block_version` (integer, ≥ 1; required)
        - `media_kind` ("speech"; required)
        - `reason` (string, one of `missing`, `stale`, `failed`, `unsupported`, `unassigned`, `unresolved`; required)
        - `source_ranges` (array of object, 1–10000 items; required)
          - `start_utf16` (integer, ≥ 0; required)
          - `end_utf16` (integer, ≥ 0; required)
      - **media_kind: "sfx"**
        - `block_id` (string, uuid; required)
        - `block_index` (integer, ≥ 0; required)
        - `block_version` (integer, ≥ 1; required)
        - `media_kind` ("sfx"; required)
        - `reason` (string, one of `missing`, `stale`, `failed`, `unsupported`, `unplaced`; required)
        - `source_ranges` (array of any, max 0 items; required)
- `assets` (array of object, max 60000 items; required): Exactly one entry per distinct asset_id referenced by asset sequential units and overlay units.
  - `asset_id` (string, uuid; required)
  - `url` (string, uri; required): Short-lived signed inline URL.
  - `expires_at` (string, date-time; required)
  - `content_type` (string, min 1 chars; required)
  - `size_bytes` (integer, ≥ 1; required)

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

#### Example request

```bash
curl "https://lyricwinter.com/api/v1/studio/sections/$SECTION_ID/playback-manifest?document_version=1&speaker_registry_version=1" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
```

### Create a media access URL

`POST /studio/media-assets/{assetId}/access-url`

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

Returns a signed URL for one audio asset: six hours for inline playback or twelve hours for download. The URL supports HTTP range requests, so audio players can seek.

#### Path parameters

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

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

- `schema_version` (1; required)
- `disposition` (string, one of `inline`, `attachment`; required)
- `filename` (string, 1–255 chars; optional)

#### Response 200

Short-lived signed media URL and asset metadata.

Fields inside `data`:

- `schema_version` (1; required)
- `asset_id` (string, uuid; required)
- `url` (string, uri; required)
- `expires_at` (string, date-time; required)
- `content_type` (string, min 1 chars; required)
- `size_bytes` (integer, ≥ 1; required)
- `disposition` (string, one of `inline`, `attachment`; 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/media-assets/$ASSET_ID/access-url" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "schema_version": 1,
  "disposition": "attachment",
  "filename": "Chapter-1.mp3"
}'
```

