API reference
Media and playback API
Check whether generation can start separately from whether audio already exists. Read per-block media freshness and generation activity, compile a playback manifest for current audio, and mint short-lived URLs. Generation availability checks plan access, voice/compiler eligibility, and ElevenLabs preparation capacity; exhausted or unverified capacity blocks new preparation, not eligible paid-plan reuse of prepared current-revision voices. It is not a promise of audio, synthesis quota, or funding. Free accounts cannot generate with ElevenLabs v4, but existing audio remains playable.
BetaUpdated
- Base URL
- https://lyricwinter.com/api/v1
- Authentication
- Authorization: Bearer lw_…
- Contract
- openapi.json
Get section media
GET/studio/sections/{sectionId}/media
studio:readReturns one entry per document block with audio freshness, independent generation activity, the latest generation/import error, and a short-lived signed playback_url for active audio. A failed retake can coexist with current playable audio. Available generation does not imply audio exists. Join by block_id. Request ?schema_version=2 for boundary_silence_handling from the active take's stored intent: timeline, fixed_in_asset, unsupported, or unavailable. The default response remains unchanged. Timeline handling applies only to boundary pauses; internal timed silences remain part of generated audio.
Path parameters
sectionIdstringrequireduuid
Query parameters
schema_versionintegerdefault 11 or omitted preserves the existing unversioned payload. 2 returns active-take boundary_silence_handling. Other values return 400.
One of
12
Response 200
Current block media read model; schema_version=2 additionally describes active-take boundary silence handling. Fields below are inside data.
One of 2 shapes:
StudioSectionMediaPayload
Current per-block media state for a Studio section.
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
schema_version: 2
Opt-in media response with authoritative active-take boundary silence handling.
schema_version2requiredsection_idstringrequireduuidplayback_duration_msinteger | null≥ 0blocksarray of objectrequired19 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_effectboundary_silence_handlingstringrequiredBoundary silence handling of the active take, not a promise about internal pauses. timeline: stored intent uses timeline-v1, so boundary pauses are assembled outside synthesis. fixed_in_asset: generated speech uses legacy baked timing. unsupported: the active media does not expose supported boundary-pause semantics. unavailable: no active media. Internal timed silences remain fixed in the asset even with timeline handling.
One of
timelinefixed_in_assetunsupportedunavailable
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"const sectionId = "<sectionId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/sections/${sectionId}/media`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
section_id = "<sectionId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/sections/{section_id}/media",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"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"
}Check generation eligibility
GET/studio/sections/{sectionId}/generation-availability
studio:readReturns each block's effective requested profile, plan access, voice/provider materialization requirements, and compiler diagnostics. ElevenLabs v4 is unavailable on free plans even for a prepared voice. New custom ElevenLabs voices require UltraWinter and a dynamic shared allocation, subject to live provider capacity. Exhausted or unverified preparation capacity makes an unprepared ElevenLabs option unavailable; prepared current-revision voices remain eligible on paid plans, including MyWinter. Choose a different engine explicitly if needed. generation.status: available does not mean audio exists or guarantee live synthesis quota or funding. Use /media for freshness, activity, errors, and playable audio. Pinned project_sound blocks use library materialization rather than synthesis and have generation: null, as do blocks without provider generation. Null does not claim a sound is present or playable.
Path parameters
sectionIdstringrequireduuid
Response 200
Current block generation eligibility, not existing-audio readiness or live provider-account health. Fields below are inside data.
section_idstringrequireduuiddocument_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1blocksarray of objectrequired2 item attributes
block_idstringrequireduuidgenerationobject | nullrequiredWhether generation can be requested under current voice/compiler authority, including ElevenLabs preparation eligibility and exhausted or unverified capacity for uncached voices. Available does not mean audio exists; check /media freshness, activity, and playback_url. This is not a general provider synthesis quota or billing check.
6 child attributes
requested_profileobjectrequiredSaved 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
statusstringrequiredOne of
availablematerialization_requiredunavailablereasonstring | nullrequiredreason_codestringOne of
provider_asset_missingacoustic_revision_changeddiagnosticsarray of objectrequired3 item attributes
codestringrequiredmin 1 charsseveritystringrequiredOne of
warningerrormessagestringrequiredmin 1 chars
optionsarray of objectrequired6 item attributes
providerstringrequiredmin 1 charsmodelstringrequiredmin 1 charsstatusstringrequiredOne of
availablematerialization_requiredunavailablereasonstring | nullrequiredreason_codestringOne of
provider_asset_missingacoustic_revision_changeddiagnosticsarray of objectrequired3 item attributes
codeobjectrequiredseverityobjectrequiredmessageobjectrequired
Errors 400, 401, 403, 404, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/sections/$SECTION_ID/generation-availability" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const sectionId = "<sectionId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/sections/${sectionId}/generation-availability`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
section_id = "<sectionId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/sections/{section_id}/generation-availability",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"section_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"document_version": 1,
"speaker_registry_version": 1,
"blocks": [
{
"block_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"generation": {
"requested_profile": {
"provider": "string",
"model": "string",
"fallback": "strict",
"controls": "strict",
"options": {}
},
"status": "available",
"reason": "string",
"reason_code": "provider_asset_missing",
"diagnostics": [
{
"code": "string",
"severity": "warning",
"message": "string"
}
],
"options": [
{
"provider": "string",
"model": "string",
"status": "available",
"reason": "string",
"reason_code": "provider_asset_missing",
"diagnostics": [
{}
]
}
]
}
}
]
},
"request_id": "req_01J9Z3K8QF4"
}Get a playback manifest
GET/studio/sections/{sectionId}/playback-manifest
studio:readCompiles the section's current speech, pauses, and sound-effect overlays into one timeline with signed asset URLs. Pass document_version and speaker_registry_version from the document. In sequential_units, unit_type: asset has the audio asset's own duration, unit_type: silence is an authored pause assembled separately on the timeline, and unit_type: spacing is an inter-block gap; sound effects are overlay_units. A speech or narration export block sums its contiguous asset and silence unit durations, excluding spacing, so do not equate its duration_ms with one asset unit's duration. Join blocks by stable block_id and per-unit records by unit_id, not by start_ms. Optional schema_version=2 adds unit_word_timings sidecars, limited to the opening 16-unit window. The window counts sequential units first, then overlays; silence and spacing count toward the limit. Sidecars identify unit_id, block_id, and asset_id with provider-aligned section-relative words or word_timing: unavailable. Later units have no sidecar in this playback response. Alignment is bound to the actual asset content hash; old/unsupported/invalid alignment is not estimated or transcribed. The default response and hashed audio manifest remain unchanged. Unknown query keys return 400. Opt in with schema_version=3 for mix_envelopes: stored 100 ms K-weighted centi-dB measurements keyed by asset_id, with unweighted measurements only for overlay assets. Missing measurements are absent. Add include_word_timings=true alongside schema_version=3 to receive asset-bound word timings for the same opening 16-unit window. False or absent keeps the existing v3 shape. V3 preserves envelopes, the manifest and its hash. Default/v1 responses are unchanged. The playback timing cap applies to v2 and opted-in v3 only; export-manifest timing reads still cover the pinned export, subject to their existing payload budget.
Path parameters
sectionIdstringrequireduuid
Query parameters
document_versionintegerrequired≥ 1Saved section document version to compile. If it no longer matches the saved section, the request fails with 409 STUDIO_PLAYBACK_STALE.
schema_versionintegerdefault 1Default/v1 retains today's payload. V2 adds word timings. V3 adds measured mix_envelopes, with optional word timings via include_word_timings=true.
One of
123speaker_registry_versionintegerrequired≥ 1Saved speaker-registry (cast) version to compile. If it no longer matches, the request fails with 409 STUDIO_PLAYBACK_STALE.
include_word_timingsbooleanWith a v3 playback manifest, true adds the optional unit_word_timings sidecar for at most the first 16 units from stored asset-bound alignment. False or absent preserves today's shape. Ignored by v1/v2; envelopes and manifest hash stay unchanged.
Response 200
Current private playback manifest and signed asset URLs. Fields below are inside data.
One of 3 shapes:
schema_version: 1
Ephemeral current playback manifest with signed asset URLs; no render run is created.
schema_version1requiredmastering_versionintegerrequired≥ 1manifest_hashstringrequiredpattern ^[a-f0-9]{64}$SHA-256 of the canonical manifest.
manifestobjectrequiredCompiled playback timeline for one saved section document and speaker-registry version.
14 child attributes
schema_version"studio-render-manifest-2"requiredproject_idstringrequireduuidsection_idstringrequireduuiddocument_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1mastering_versionintegerrequired≥ 1mastering_profile_hashstringrequiredpattern ^[a-f0-9]{64}$mastering_profileobjectrequired10 child attributes
schema_version1requiredenabledbooleanrequiredtarget_lufsnumberrequired-30–-10strengthnumberrequired0–1max_boost_dbnumberrequired0–24max_reduction_dbnumberrequired0–24silence_threshold_lufsnumberrequired-120–-20peak_ceiling_dbnumberrequired-12–-0.1speaker_adjustments_dbmap of numberrequiredsfx_bus_gain_dbnumberrequired-24–24default 0
completenessstringrequiredcomplete exactly when gaps is empty.
One of
partialcompleteduration_msintegerrequired≥ 0Latest end point of any sequential or overlay unit.
sequential_unitsarray of objectrequiredmax 50000 itemsContiguous from 0 ms in canonical block order; unit IDs are unique across sequential and overlay units.
One of 3 shapes:
unit_type: "asset"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1rendition_idstringrequireduuidrendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$unit_type"asset"requiredasset_idstringrequireduuidKey into the payload's assets array.
asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$source_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
speaker_idstringrequireduuidanalysis_integrated_lufsnumberrequired-120–12analysis_sample_peak_dbfsnumberrequired-200–12effective_gain_dbnumberrequired-24–24
unit_type: "silence"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1rendition_idstringrequireduuidrendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$unit_type"silence"required
unit_type: "spacing", spacing_kind: "inter_passage"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1unit_type"spacing"requiredspacing_kind"inter_passage"required
overlay_unitsarray of objectrequiredmax 10000 itemsOrdered by start_ms, block_index, block_id, unit_id.
13 item attributes
unit_type"sfx"requiredunit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1intent_hashstringrequiredpattern ^[a-f0-9]{64}$asset_idstringrequireduuidKey into the payload's assets array.
asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$start_msintegerrequired≥ 0duration_msintegerrequired≥ 1gain_dbnumberrequired-60–24fade_in_msintegerrequired≥ 0fade_out_msintegerrequired≥ 0
timed_text_unitsarray of objectrequiredmax 50000 itemsOrdered by start_ms, block_index, block_id, unit_id.
10 item attributes
unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1speaker_idstringrequireduuidstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1textstringrequired1–100000 charstext_hashstringrequiredpattern ^[a-f0-9]{64}$source_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
gapsarray of objectrequiredmax 50000 itemsOrdered by block_index, media_kind, block_id.
One of 2 shapes:
media_kind: "speech"block_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1media_kind"speech"requiredreasonstringrequiredOne of
missingstalefailedunsupportedunassignedunresolvedsource_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
media_kind: "sfx"block_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1media_kind"sfx"requiredreasonstringrequiredOne of
missingstalefailedunsupportedunplacedsource_rangesarray of anyrequiredmax 0 items
assetsarray of objectrequiredmax 60000 itemsExactly one entry per distinct asset_id referenced by asset sequential units and overlay units.
5 item attributes
asset_idstringrequireduuidurlstringrequireduriShort-lived signed inline URL.
expires_atstringrequireddate-timecontent_typestringrequiredmin 1 charssize_bytesintegerrequired≥ 1
schema_version: 2
Opt-in playback payload with take-bound word timing sidecars. manifest_hash still hashes the unchanged audio manifest, not these optional sidecars.
schema_version2requiredmastering_versionintegerrequired≥ 1manifest_hashstringrequiredpattern ^[a-f0-9]{64}$SHA-256 of the canonical manifest.
manifestobjectrequiredCompiled playback timeline for one saved section document and speaker-registry version.
14 child attributes
schema_version"studio-render-manifest-2"requiredproject_idstringrequireduuidsection_idstringrequireduuiddocument_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1mastering_versionintegerrequired≥ 1mastering_profile_hashstringrequiredpattern ^[a-f0-9]{64}$mastering_profileobjectrequired10 child attributes
schema_version1requiredenabledbooleanrequiredtarget_lufsnumberrequired-30–-10strengthnumberrequired0–1max_boost_dbnumberrequired0–24max_reduction_dbnumberrequired0–24silence_threshold_lufsnumberrequired-120–-20peak_ceiling_dbnumberrequired-12–-0.1speaker_adjustments_dbmap of numberrequiredsfx_bus_gain_dbnumberrequired-24–24default 0
completenessstringrequiredcomplete exactly when gaps is empty.
One of
partialcompleteduration_msintegerrequired≥ 0Latest end point of any sequential or overlay unit.
sequential_unitsarray of objectrequiredmax 50000 itemsContiguous from 0 ms in canonical block order; unit IDs are unique across sequential and overlay units.
One of 3 shapes:
unit_type: "asset"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1rendition_idstringrequireduuidrendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$unit_type"asset"requiredasset_idstringrequireduuidKey into the payload's assets array.
asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$source_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
speaker_idstringrequireduuidanalysis_integrated_lufsnumberrequired-120–12analysis_sample_peak_dbfsnumberrequired-200–12effective_gain_dbnumberrequired-24–24
unit_type: "silence"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1rendition_idstringrequireduuidrendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$unit_type"silence"required
unit_type: "spacing", spacing_kind: "inter_passage"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1unit_type"spacing"requiredspacing_kind"inter_passage"required
overlay_unitsarray of objectrequiredmax 10000 itemsOrdered by start_ms, block_index, block_id, unit_id.
13 item attributes
unit_type"sfx"requiredunit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1intent_hashstringrequiredpattern ^[a-f0-9]{64}$asset_idstringrequireduuidKey into the payload's assets array.
asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$start_msintegerrequired≥ 0duration_msintegerrequired≥ 1gain_dbnumberrequired-60–24fade_in_msintegerrequired≥ 0fade_out_msintegerrequired≥ 0
timed_text_unitsarray of objectrequiredmax 50000 itemsOrdered by start_ms, block_index, block_id, unit_id.
10 item attributes
unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1speaker_idstringrequireduuidstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1textstringrequired1–100000 charstext_hashstringrequiredpattern ^[a-f0-9]{64}$source_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
gapsarray of objectrequiredmax 50000 itemsOrdered by block_index, media_kind, block_id.
One of 2 shapes:
media_kind: "speech"block_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1media_kind"speech"requiredreasonstringrequiredOne of
missingstalefailedunsupportedunassignedunresolvedsource_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
media_kind: "sfx"block_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1media_kind"sfx"requiredreasonstringrequiredOne of
missingstalefailedunsupportedunplacedsource_rangesarray of anyrequiredmax 0 items
assetsarray of objectrequiredmax 60000 itemsExactly one entry per distinct asset_id referenced by asset sequential units and overlay units.
5 item attributes
asset_idstringrequireduuidurlstringrequireduriShort-lived signed inline URL.
expires_atstringrequireddate-timecontent_typestringrequiredmin 1 charssize_bytesintegerrequired≥ 1
unit_word_timingsarray of objectrequiredmax 60000 itemsOne of 2 shapes:
word_timing: "provider"unit_idstringrequireduuidblock_idstringrequireduuidasset_idstringrequireduuidword_timing"provider"requiredwordsarray of objectrequired1–10000 items3 item attributes
textstringrequired1–4096 charsstart_msintegerrequired≥ 0end_msintegerrequired≥ 0
word_timing: "unavailable"unit_idstringrequireduuidblock_idstringrequireduuidasset_idstringrequireduuidword_timing"unavailable"required
schema_version: 3
Opt-in v3 playback. The manifest, manifest_hash, mastering_version and signed assets retain v1 semantics. mix_envelopes does not affect manifest_hash. Optional include_word_timings=true adds a bounded opening window of asset-bound word timings. Database read failures fail the request.
schema_version3requiredmastering_versionintegerrequired≥ 1manifest_hashstringrequiredpattern ^[a-f0-9]{64}$SHA-256 of the canonical manifest.
manifestobjectrequiredCompiled playback timeline for one saved section document and speaker-registry version.
14 child attributes
schema_version"studio-render-manifest-2"requiredproject_idstringrequireduuidsection_idstringrequireduuiddocument_versionintegerrequired≥ 1speaker_registry_versionintegerrequired≥ 1mastering_versionintegerrequired≥ 1mastering_profile_hashstringrequiredpattern ^[a-f0-9]{64}$mastering_profileobjectrequired10 child attributes
schema_version1requiredenabledbooleanrequiredtarget_lufsnumberrequired-30–-10strengthnumberrequired0–1max_boost_dbnumberrequired0–24max_reduction_dbnumberrequired0–24silence_threshold_lufsnumberrequired-120–-20peak_ceiling_dbnumberrequired-12–-0.1speaker_adjustments_dbmap of numberrequiredsfx_bus_gain_dbnumberrequired-24–24default 0
completenessstringrequiredcomplete exactly when gaps is empty.
One of
partialcompleteduration_msintegerrequired≥ 0Latest end point of any sequential or overlay unit.
sequential_unitsarray of objectrequiredmax 50000 itemsContiguous from 0 ms in canonical block order; unit IDs are unique across sequential and overlay units.
One of 3 shapes:
unit_type: "asset"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1rendition_idstringrequireduuidrendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$unit_type"asset"requiredasset_idstringrequireduuidKey into the payload's assets array.
asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$source_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
speaker_idstringrequireduuidanalysis_integrated_lufsnumberrequired-120–12analysis_sample_peak_dbfsnumberrequired-200–12effective_gain_dbnumberrequired-24–24
unit_type: "silence"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1rendition_idstringrequireduuidrendition_intent_hashstringrequiredpattern ^[a-f0-9]{64}$unit_type"silence"required
unit_type: "spacing", spacing_kind: "inter_passage"unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1block_kindstringrequiredOne of
speechnarrationstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1unit_type"spacing"requiredspacing_kind"inter_passage"required
overlay_unitsarray of objectrequiredmax 10000 itemsOrdered by start_ms, block_index, block_id, unit_id.
13 item attributes
unit_type"sfx"requiredunit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1intent_hashstringrequiredpattern ^[a-f0-9]{64}$asset_idstringrequireduuidKey into the payload's assets array.
asset_content_hashstringrequiredpattern ^[a-f0-9]{64}$start_msintegerrequired≥ 0duration_msintegerrequired≥ 1gain_dbnumberrequired-60–24fade_in_msintegerrequired≥ 0fade_out_msintegerrequired≥ 0
timed_text_unitsarray of objectrequiredmax 50000 itemsOrdered by start_ms, block_index, block_id, unit_id.
10 item attributes
unit_idstringrequireduuidblock_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1speaker_idstringrequireduuidstart_msintegerrequired≥ 0duration_msintegerrequired≥ 1textstringrequired1–100000 charstext_hashstringrequiredpattern ^[a-f0-9]{64}$source_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
gapsarray of objectrequiredmax 50000 itemsOrdered by block_index, media_kind, block_id.
One of 2 shapes:
media_kind: "speech"block_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1media_kind"speech"requiredreasonstringrequiredOne of
missingstalefailedunsupportedunassignedunresolvedsource_rangesarray of objectrequired1–10000 items2 item attributes
start_utf16integerrequired≥ 0end_utf16integerrequired≥ 0
media_kind: "sfx"block_idstringrequireduuidblock_indexintegerrequired≥ 0block_versionintegerrequired≥ 1media_kind"sfx"requiredreasonstringrequiredOne of
missingstalefailedunsupportedunplacedsource_rangesarray of anyrequiredmax 0 items
assetsarray of objectrequiredmax 60000 itemsExactly one entry per distinct asset_id referenced by asset sequential units and overlay units.
5 item attributes
asset_idstringrequireduuidurlstringrequireduriShort-lived signed inline URL.
expires_atstringrequireddate-timecontent_typestringrequiredmin 1 charssize_bytesintegerrequired≥ 1
mix_envelopesarray of objectrequiredmax 60000 itemsAt most one stored envelope per referenced asset. Missing measurements are omitted, never synthesized. No unreferenced assets are included.
6 item attributes
asset_idstringrequireduuidenvelope_version"studio-energy-envelope-1"requiredblock_ms100requiredduration_msintegerrequired≥ 0k_weighted_cdbarray of integerrequiredunweighted_cdbarray of integer | nullrequired
unit_word_timingsarray of objectmax 60000 itemsIncluded only when include_word_timings=true is requested. At most the first 16 units use stored asset-bound alignment, with section-relative words or unavailable entries. Use the windowed word-timings read as playback advances. Does not affect the manifest or its hash.
One of 2 shapes:
word_timing: "provider"unit_idstringrequireduuidblock_idstringrequireduuidasset_idstringrequireduuidword_timing"provider"requiredwordsarray of objectrequired1–10000 items3 item attributes
textstringrequired1–4096 charsstart_msintegerrequired≥ 0end_msintegerrequired≥ 0
word_timing: "unavailable"unit_idstringrequireduuidblock_idstringrequireduuidasset_idstringrequireduuidword_timing"unavailable"required
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"const sectionId = "<sectionId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/sections/${sectionId}/playback-manifest?document_version=1&speaker_registry_version=1`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
section_id = "<sectionId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/sections/{section_id}/playback-manifest?document_version=1&speaker_registry_version=1",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"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
studio:readReturns 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_version1requireddispositionstringrequiredOne of
inlineattachmentfilenamestring1–255 chars
Response 200
Short-lived signed media URL and asset metadata. Fields below are inside data.
schema_version1requiredasset_idstringrequireduuidurlstringrequireduriexpires_atstringrequireddate-timecontent_typestringrequiredmin 1 charssize_bytesintegerrequired≥ 1dispositionstringrequiredOne of
inlineattachment
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"
}'const assetId = "<assetId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/media-assets/${assetId}/access-url`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"schema_version": 1,
"disposition": "attachment",
"filename": "Chapter-1.mp3"
}),
});
const { data, error, request_id } = await response.json();import os
import requests
asset_id = "<assetId>"
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/media-assets/{asset_id}/access-url",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"schema_version": 1,
"disposition": "attachment",
"filename": "Chapter-1.mp3"
},
)
payload = response.json(){
"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"
}Listen to existing Studio audio
POST/studio/media-assets/{assetId}/reviews
studio:readAnalyze the actual bytes of an owned speech, sound-effect or finished render asset for review, transcription or timing. Requires studio:read and project read permission. Maximum 10 MiB and 300 seconds of positive stored duration; duration_basis identifies stored metadata, not a new decoded measurement. Returns untrusted model observations. No customer words, audio generation or export. Each call incurs bounded analysis cost and is not idempotent. Unknown outcomes must not be automatically retried.
Path parameters
assetIdstringrequireduuid
Request body application/json
focusstringdefault "review"One of
reviewtranscribetiming
Response 200
Untrusted model observation bound to the immutable audio asset. Fields below are inside data.
schema_version1requiredasset_idstringrequireduuidgenerationintegerrequired≥ 1content_hashstringrequiredpattern ^[a-f0-9]{64}$duration_msintegerrequired1–300000duration_basis"stored_asset_metadata"requiredfocusstringrequiredOne of
reviewtranscribetimingprovider"gemini"requiredmodel"gemini-3.5-flash-lite"requireduntrustedtruerequiredobservationobjectrequired4 child attributes
summarystringrequiredmax 1500 charstranscriptstringrequiredmax 20000 charsfindingsarray of objectrequiredmax 20 items4 item attributes
startSecondsnumberrequired0–300endSecondsnumberrequired0–300kindstringrequiredOne of
speechdeliverypronunciationnoisemusicotherdescriptionstringrequiredmax 500 chars
segmentsarray of objectrequiredmax 100 items3 item attributes
startSecondsnumberrequired0–300endSecondsnumberrequired0–300textstringrequiredmax 1500 chars
Errors 400, 401, 403, 404, 409, 413, 422, 502, 503 use the standard error envelope.
curl -X POST "https://lyricwinter.com/api/v1/studio/media-assets/$ASSET_ID/reviews" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const assetId = "<assetId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/media-assets/${assetId}/reviews`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
const { data, error, request_id } = await response.json();import os
import requests
asset_id = "<assetId>"
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/media-assets/{asset_id}/reviews",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={},
)
payload = response.json(){
"data": {
"schema_version": 1,
"asset_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"generation": 1,
"content_hash": "string",
"duration_ms": 1,
"duration_basis": "stored_asset_metadata",
"focus": "review",
"provider": "gemini",
"model": "gemini-3.5-flash-lite",
"untrusted": true,
"observation": {
"summary": "string",
"transcript": "string",
"findings": [
{
"startSeconds": 0,
"endSeconds": 0,
"kind": "speech",
"description": "string"
}
],
"segments": [
{
"startSeconds": 0,
"endSeconds": 0,
"text": "A bell rang. \"Who is there?\" Mira asked."
}
]
}
},
"request_id": "req_01J9Z3K8QF4"
}