Skip to content

API reference

Media and playback API

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.

BetaUpdated

Base URL
https://lyricwinter.com/api/v1
Authentication
Authorization: Bearer lw_…
Contract
openapi.json

Get section media

GET/studio/sections/{sectionId}/media

Scope studio:read

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

  • sectionIdstringrequireduuid

Response 200

Current block media read model. Fields below are inside data.

  • section_idstringrequireduuid
  • playback_duration_msinteger | nullrequired≥ 0

    Duration of the newest saved render manifest for the section's current document and speaker-registry versions; null when none exists.

  • blocksarray of objectrequired

    One entry per document block, in document order.

    18 item attributes
    • block_idstringrequireduuid
    • freshnessstringrequired

      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.

      One ofabsentcurrentstaleunsupported

    • activitystringrequired

      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.

      One ofidlegeneratingfailed

    • active_block_versioninteger | nullrequired≥ 1

      Block version the active rendition was requested for.

    • requested_block_versioninteger | nullrequired≥ 1

      Block version of the pending rendition or import, if any.

    • active_rendition_idstring | nullrequireduuid
    • audio_version_countintegerrequired≥ 0

      Number of completed audio versions for the block.

    • generation_batch_idstring | nullrequireduuid

      Generation batch of the pending rendition.

    • playback_urlstring | nullrequireduri

      Short-lived signed URL for the active rendition's audio; null without an active asset.

    • playback_url_expires_atstring | nullrequireddate-time
    • content_typestring | nullrequired
    • size_bytesinteger | nullrequired≥ 1
    • analysis_integrated_lufsnumber | nullrequired-120–24
    • analysis_sample_peak_dbfsnumber | nullrequired-200–24
    • providerstring | nullrequired

      Provider that actually produced the active rendition (stored metadata for imports).

    • modelstring | nullrequired

      Model that actually produced the active rendition (stored metadata for imports).

    • errorstring | nullrequired

      Latest generation or import error message.

    • stale_reasonsarray of string

      Present for speech, narration, and sfx blocks; non-empty only when freshness is stale.

      One ofblock_kindtextpronunciationexcluded_texttimingvoicegeneration_profiledelivery_controlssound_effect

Errors 400, 401, 403, 404, 500, 503 use the standard error envelope.

curl "https://lyricwinter.com/api/v1/studio/sections/$SECTION_ID/media" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
Response 200 (example)
{
  "data": {
    "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"
        ]
      }
    ]
  },
  "request_id": "req_01J9Z3K8QF4"
}

Get a playback manifest

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

Scope studio:read

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

  • sectionIdstringrequireduuid

Query parameters

  • document_versionintegerrequired≥ 1

    Saved section document version to compile. If it no longer matches the saved section, the request fails with 409 STUDIO_PLAYBACK_STALE.

  • speaker_registry_versionintegerrequired≥ 1

    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 below are inside data.

  • schema_version1required
  • mastering_versionintegerrequired≥ 1
  • manifest_hashstringrequiredpattern ^[a-f0-9]{64}$

    SHA-256 of the canonical manifest.

  • manifestobjectrequired

    Compiled playback timeline for one saved section document and speaker-registry version.

    14 child attributes
    • schema_version"studio-render-manifest-2"required
    • project_idstringrequireduuid
    • section_idstringrequireduuid
    • document_versionintegerrequired≥ 1
    • speaker_registry_versionintegerrequired≥ 1
    • mastering_versionintegerrequired≥ 1
    • mastering_profile_hashstringrequiredpattern ^[a-f0-9]{64}$
    • mastering_profileobjectrequired
      10 child attributes
      • schema_version1required
      • enabledbooleanrequired
      • target_lufsnumberrequired-30–-10
      • strengthnumberrequired0–1
      • max_boost_dbnumberrequired0–24
      • max_reduction_dbnumberrequired0–24
      • silence_threshold_lufsnumberrequired-120–-20
      • peak_ceiling_dbnumberrequired-12–-0.1
      • speaker_adjustments_dbmap of numberrequired
      • sfx_bus_gain_dbnumberrequired-24–24default 0
    • completenessstringrequired

      complete exactly when gaps is empty.

      One ofpartialcomplete

    • duration_msintegerrequired≥ 0

      Latest end point of any sequential or overlay unit.

    • sequential_unitsarray of objectrequiredmax 50000 items

      Contiguous from 0 ms in canonical block order; unit IDs are unique across sequential and overlay units.

      One of 3 shapes:

      unit_type: "asset"
      • unit_idstringrequireduuid
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • block_kindstringrequired

        One ofspeechnarration

      • start_msintegerrequired≥ 0
      • duration_msintegerrequired≥ 1
      • rendition_idstringrequireduuid
      • rendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$
      • unit_type"asset"required
      • asset_idstringrequireduuid

        Key into the payload's assets array.

      • asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$
      • source_rangesarray of objectrequired1–10000 items
        2 item attributes
        • start_utf16integerrequired≥ 0
        • end_utf16integerrequired≥ 0
      • speaker_idstringrequireduuid
      • analysis_integrated_lufsnumberrequired-120–12
      • analysis_sample_peak_dbfsnumberrequired-200–12
      • effective_gain_dbnumberrequired-24–24
      unit_type: "silence"
      • unit_idstringrequireduuid
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • block_kindstringrequired

        One ofspeechnarration

      • start_msintegerrequired≥ 0
      • duration_msintegerrequired≥ 1
      • rendition_idstringrequireduuid
      • rendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$
      • unit_type"silence"required
      unit_type: "spacing", spacing_kind: "inter_passage"
      • unit_idstringrequireduuid
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • block_kindstringrequired

        One ofspeechnarration

      • start_msintegerrequired≥ 0
      • duration_msintegerrequired≥ 1
      • unit_type"spacing"required
      • spacing_kind"inter_passage"required
    • overlay_unitsarray of objectrequiredmax 10000 items

      Ordered by start_ms, block_index, block_id, unit_id.

      13 item attributes
      • unit_type"sfx"required
      • unit_idstringrequireduuid
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • intent_hashstringrequiredpattern ^[a-f0-9]{64}$
      • asset_idstringrequireduuid

        Key into the payload's assets array.

      • asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$
      • start_msintegerrequired≥ 0
      • duration_msintegerrequired≥ 1
      • gain_dbnumberrequired-60–24
      • fade_in_msintegerrequired≥ 0
      • fade_out_msintegerrequired≥ 0
    • timed_text_unitsarray of objectrequiredmax 50000 items

      Ordered by start_ms, block_index, block_id, unit_id.

      10 item attributes
      • unit_idstringrequireduuid
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • speaker_idstringrequireduuid
      • start_msintegerrequired≥ 0
      • duration_msintegerrequired≥ 1
      • textstringrequired1–100000 chars
      • text_hashstringrequiredpattern ^[a-f0-9]{64}$
      • source_rangesarray of objectrequired1–10000 items
        2 item attributes
        • start_utf16integerrequired≥ 0
        • end_utf16integerrequired≥ 0
    • gapsarray of objectrequiredmax 50000 items

      Ordered by block_index, media_kind, block_id.

      One of 2 shapes:

      media_kind: "speech"
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • media_kind"speech"required
      • reasonstringrequired

        One ofmissingstalefailedunsupportedunassignedunresolved

      • source_rangesarray of objectrequired1–10000 items
        2 item attributes
        • start_utf16integerrequired≥ 0
        • end_utf16integerrequired≥ 0
      media_kind: "sfx"
      • block_idstringrequireduuid
      • block_indexintegerrequired≥ 0
      • block_versionintegerrequired≥ 1
      • media_kind"sfx"required
      • reasonstringrequired

        One ofmissingstalefailedunsupportedunplaced

      • source_rangesarray of anyrequiredmax 0 items
  • assetsarray of objectrequiredmax 60000 items

    Exactly one entry per distinct asset_id referenced by asset sequential units and overlay units.

    5 item attributes
    • asset_idstringrequireduuid
    • urlstringrequireduri

      Short-lived signed inline URL.

    • expires_atstringrequireddate-time
    • content_typestringrequiredmin 1 chars
    • size_bytesintegerrequired≥ 1

Errors 400, 401, 403, 409, 500, 502, 503 use the standard error envelope.

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"
Response 200 (example)
{
  "data": {
    "schema_version": 1,
    "mastering_version": 1,
    "manifest_hash": "string",
    "manifest": {
      "schema_version": "studio-render-manifest-2",
      "project_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
      "section_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
      "document_version": 1,
      "speaker_registry_version": 1,
      "mastering_version": 1,
      "mastering_profile_hash": "string",
      "mastering_profile": {
        "schema_version": 1,
        "enabled": true,
        "target_lufs": -30,
        "strength": 0,
        "max_boost_db": 0,
        "max_reduction_db": 0,
        "silence_threshold_lufs": -120,
        "peak_ceiling_db": -12,
        "speaker_adjustments_db": {},
        "sfx_bus_gain_db": 0
      },
      "completeness": "partial",
      "duration_ms": 1,
      "sequential_units": [
        {
          "unit_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
          "block_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
          "block_index": 1,
          "block_version": 1,
          "block_kind": "speech",
          "start_ms": 1,
          "duration_ms": 1,
          "rendition_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
          "rendition_intent_hash": "string",
          "unit_type": "asset",
          "asset_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
          "asset_content_hash": "string",
          "source_ranges": [
            {
              "start_utf16": 1,
              "end_utf16": 1
            }
          ],
          "speaker_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
          "analysis_integrated_lufs": -120,
          "analysis_sample_peak_dbfs": -200,
          "effective_gain_db": -24
        }
      ],
      "overlay_units": [
        {
          "unit_type": "sfx",
          "unit_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
          "block_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
          "block_index": 1,
          "block_version": 1,
          "intent_hash": "string",
          "asset_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
          "asset_content_hash": "string",
          "start_ms": 1,
          "duration_ms": 1,
          "gain_db": -60,
          "fade_in_ms": 1,
          "fade_out_ms": 1
        }
      ],
      "timed_text_units": [
        {
          "unit_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
          "block_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
          "block_index": 1,
          "block_version": 1,
          "speaker_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
          "start_ms": 1,
          "duration_ms": 1,
          "text": "A bell rang. \"Who is there?\" Mira asked.",
          "text_hash": "string",
          "source_ranges": [
            {
              "start_utf16": 1,
              "end_utf16": 1
            }
          ]
        }
      ],
      "gaps": [
        {
          "block_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
          "block_index": 1,
          "block_version": 1,
          "media_kind": "speech",
          "reason": "missing",
          "source_ranges": [
            {
              "start_utf16": 1,
              "end_utf16": 1
            }
          ]
        }
      ]
    },
    "assets": [
      {
        "asset_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
        "url": "https://lyricwinter.com/…",
        "expires_at": "2026-09-30T17:00:00.000Z",
        "content_type": "string",
        "size_bytes": 1
      }
    ]
  },
  "request_id": "req_01J9Z3K8QF4"
}

Create a media access URL

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

Scope studio:read

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

  • assetIdstringrequireduuid

Request body application/json

  • schema_version1required
  • dispositionstringrequired

    One ofinlineattachment

  • filenamestring1–255 chars

Response 200

Short-lived signed media URL and asset metadata. Fields below are inside data.

  • schema_version1required
  • asset_idstringrequireduuid
  • urlstringrequireduri
  • expires_atstringrequireddate-time
  • content_typestringrequiredmin 1 chars
  • size_bytesintegerrequired≥ 1
  • dispositionstringrequired

    One ofinlineattachment

Errors 400, 401, 403, 404, 409, 500, 503 use the standard error envelope.

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"
}'
Response 200 (example)
{
  "data": {
    "schema_version": 1,
    "asset_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
    "url": "https://lyricwinter.com/…",
    "expires_at": "2026-09-30T17:00:00.000Z",
    "content_type": "string",
    "size_bytes": 1,
    "disposition": "inline"
  },
  "request_id": "req_01J9Z3K8QF4"
}