API reference
Character voice design API
Design a Studio character voice, read its exact job and candidates, select before expiry, or request cancellation. Retain original mutation/request/job identities. Voice creation does not generate speech; assignment_outcome and the current document determine whether casting succeeded. The project preference selects the engine for future designs independently of the sample-design provider.
BetaUpdated
- Base URL
- https://lyricwinter.com/api/v1
- Authentication
- Authorization: Bearer lw_…
- Contract
- openapi.json
Read the engine for future character voices
GET/studio/projects/{projectId}/new-voice-engine
studio:readRead the project's current new-voice synthesis engine. Null means Automatic. This is separate from the sample-design provider and does not change voices or create audio. Requires project.read.
Path parameters
projectIdstringrequireduuid
Response 200
Project engine preference; null means Automatic. Fields below are inside data.
schema_versionstringrequiredOne of
studio-new-voice-engine-1modelstring | nullrequiredOne of
fishaudio-drama-3eleven_v4inworld-2cartesia-sonic-3.6lightning_v3.1fishaudio-s2.1-proinworld-1.5-maxinworld-1.5-minicartesia-sonic-3.5fishaudiof5tts
Errors 400, 401, 403, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/new-voice-engine" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const projectId = "<projectId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/new-voice-engine`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/new-voice-engine",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"schema_version": "studio-new-voice-engine-1",
"model": "fishaudio-drama-3"
},
"request_id": "req_01J9Z3K8QF4"
}Choose the engine for future character voices
PATCH/studio/projects/{projectId}/new-voice-engine
studio:writeSave an eligible engine preference, or null for Automatic, with project.manage permission. Future designs capture it; existing voices and audio remain unchanged. This setter has no versioned mutation receipt: after uncertainty read and reconcile rather than automatically overwriting an intervening edit.
Path parameters
projectIdstringrequireduuid
Request body application/json
schema_versionstringrequiredOne of
studio-new-voice-engine-1modelstring | nullrequiredOne of
fishaudio-drama-3eleven_v4inworld-2cartesia-sonic-3.6lightning_v3.1fishaudio-s2.1-proinworld-1.5-maxinworld-1.5-minicartesia-sonic-3.5fishaudiof5tts
Response 200
Saved project engine preference. Fields below are inside data.
schema_versionstringrequiredOne of
studio-new-voice-engine-1modelstring | nullrequiredOne of
fishaudio-drama-3eleven_v4inworld-2cartesia-sonic-3.6lightning_v3.1fishaudio-s2.1-proinworld-1.5-maxinworld-1.5-minicartesia-sonic-3.5fishaudiof5tts
Errors 400, 401, 403, 500 use the standard error envelope.
curl -X PATCH "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/new-voice-engine" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_version": "studio-new-voice-engine-1",
"model": "fishaudio-drama-3"
}'const projectId = "<projectId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/new-voice-engine`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"schema_version": "studio-new-voice-engine-1",
"model": "fishaudio-drama-3"
}),
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
response = requests.request(
"PATCH",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/new-voice-engine",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"schema_version": "studio-new-voice-engine-1",
"model": "fishaudio-drama-3"
},
)
payload = response.json(){
"data": {
"schema_version": "studio-new-voice-engine-1",
"model": "fishaudio-drama-3"
},
"request_id": "req_01J9Z3K8QF4"
}Find an active character voice design
GET/studio/projects/{projectId}/speakers/{speakerId}/voice-materialization-jobs
studio:readReturn the latest queued, running or awaiting-selection AI voice design for this project/speaker, or null. This is not an original-operation lookup or proof that prior work failed; retain and read an exact confirmed job ID for recovery.
Path parameters
projectIdstringrequireduuidspeakerIdstringrequireduuid
Response 200
Active voice design or null when none is active. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Errors 400, 401, 403, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/speakers/$SPEAKER_ID/voice-materialization-jobs" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const projectId = "<projectId>";
const speakerId = "<speakerId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/speakers/${speakerId}/voice-materialization-jobs`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
project_id = "<projectId>"
speaker_id = "<speakerId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/speakers/{speaker_id}/voice-materialization-jobs",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"project_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"speaker_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"source_voice_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"materialization_kind": "provider_asset",
"provider": "inworld",
"model": "string",
"selection_mode": "automatic",
"requested_candidate_count": 1,
"status": "queued",
"selection_expires_at": "2026-09-30T17:00:00.000Z",
"selected_candidate_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"cancel_requested_at": "2026-09-30T17:00:00.000Z",
"output_voice_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"output_provider_asset_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"assignment_outcome": "not_applicable",
"error_code": "string",
"error_message": "string",
"created_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"candidates": [
{
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"candidate_index": 1,
"preview_url": "https://lyricwinter.com/…",
"preview_text": "string",
"duration_ms": 1,
"status": "available"
}
]
},
"request_id": "req_01J9Z3K8QF4"
}Design or prepare a character voice
POST/studio/projects/{projectId}/speakers/{speakerId}/voice-materialization-jobs
studio:writeRetry with the same client_mutation_idSubmit the canonical voice materialization request with its original client_mutation_id. New AI designs use schema_version 2 and optional voice_direction; provider preparation and legacy v1 remain supported. Manual mode exposes up to three candidates; automatic mode requires one. The ordinary server captures authority and the project's casting engine. Recover only the identical original request after uncertainty; never substitute another voice or mutation. This operation does not generate speech.
Path parameters
projectIdstringrequireduuidspeakerIdstringrequireduuid
Request body application/json
One of 3 shapes:
schema_version: 1, materialization_kind: "provider_asset"
schema_version1requiredclient_mutation_idstringrequireduuidmaterialization_kind"provider_asset"expected_source_voice_idstringuuidprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelanyrequiredOne of
inworld-2cartesia-sonic-3.5fishaudio-s2.1-prolightning_v3.1eleven_v4phonon-31m-en
schema_version: 1, materialization_kind: "ai_voice_creation"
schema_version1requiredclient_mutation_idstringrequireduuidmaterialization_kind"ai_voice_creation"requiredsection_idstringrequireduuidactor_session_idstringrequireduuidprovideranyrequiredOne of
inworldfish_audiomodelanyrequiredOne of
inworld-2fishaudio-s2.1-proselection_modeanyrequiredOne of
automaticmanualcandidate_countintegerrequired1–3custom_promptstring30–250 chars
schema_version: 2, materialization_kind: "ai_voice_creation"
schema_version2requiredclient_mutation_idstringrequireduuidmaterialization_kind"ai_voice_creation"requiredsection_idstringrequireduuidactor_session_idstringrequireduuidprovideranyrequiredOne of
inworldfish_audiomodelanyrequiredOne of
inworld-2fishaudio-s2.1-proselection_modeanyrequiredOne of
automaticmanualcandidate_countintegerrequired1–3voice_directionstring30–250 chars
Response 200
The provider voice was already ready. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Response 202
Durable voice preparation accepted. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Errors 400, 401, 403, 404, 409, 429, 500, 502 use the standard error envelope.
curl -X POST "https://lyricwinter.com/api/v1/studio/projects/$PROJECT_ID/speakers/$SPEAKER_ID/voice-materialization-jobs" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'const projectId = "<projectId>";
const speakerId = "<speakerId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/projects/${projectId}/speakers/${speakerId}/voice-materialization-jobs`, {
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
project_id = "<projectId>"
speaker_id = "<speakerId>"
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/projects/{project_id}/speakers/{speaker_id}/voice-materialization-jobs",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={},
)
payload = response.json(){
"data": {
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"project_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"speaker_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"source_voice_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"materialization_kind": "provider_asset",
"provider": "inworld",
"model": "string",
"selection_mode": "automatic",
"requested_candidate_count": 1,
"status": "queued",
"selection_expires_at": "2026-09-30T17:00:00.000Z",
"selected_candidate_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"cancel_requested_at": "2026-09-30T17:00:00.000Z",
"output_voice_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"output_provider_asset_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"assignment_outcome": "not_applicable",
"error_code": "string",
"error_message": "string",
"created_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"candidates": [
{
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"candidate_index": 1,
"preview_url": "https://lyricwinter.com/…",
"preview_text": "string",
"duration_ms": 1,
"status": "available"
}
]
},
"request_id": "req_01J9Z3K8QF4"
}Read a character voice job
GET/studio/voice-materialization-jobs/{jobId}
studio:readRead the original job's status, candidate previews and expiry, output identities, cancellation and assignment_outcome. A completed voice with speaker_changed was not cast; verify the current document before generating speech. Optional wait_seconds from 0 to 25 waits for a status change; terminal or actionable states return immediately.
Path parameters
jobIdstringrequireduuid
Query parameters
wait_secondsinteger0–25Optional bounded wait for a status change. Returns immediately for terminal or actionable jobs; omitted or 0 reads immediately. Available to every Studio client.
Response 200
Current voice preparation state. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Errors 400, 401, 403, 404, 500 use the standard error envelope.
curl "https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/$JOB_ID" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const jobId = "<jobId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/${jobId}`, {
method: "GET",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
job_id = "<jobId>"
response = requests.request(
"GET",
f"https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/{job_id}",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"project_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"speaker_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"source_voice_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"materialization_kind": "provider_asset",
"provider": "inworld",
"model": "string",
"selection_mode": "automatic",
"requested_candidate_count": 1,
"status": "queued",
"selection_expires_at": "2026-09-30T17:00:00.000Z",
"selected_candidate_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"cancel_requested_at": "2026-09-30T17:00:00.000Z",
"output_voice_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"output_provider_asset_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"assignment_outcome": "not_applicable",
"error_code": "string",
"error_message": "string",
"created_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"candidates": [
{
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"candidate_index": 1,
"preview_url": "https://lyricwinter.com/…",
"preview_text": "string",
"duration_ms": 1,
"status": "available"
}
]
},
"request_id": "req_01J9Z3K8QF4"
}Cancel a character voice job
POST/studio/voice-materialization-jobs/{jobId}/cancel
studio:writeRequest cancellation of the exact original job and read its actual state. Pending cancellation is not completed cleanup or immediate hard deletion and does not reverse existing casting. Do not create replacement work to recover an unknown response.
Path parameters
jobIdstringrequireduuid
Response 200
Current cancelled or canceling preparation state. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Errors 400, 401, 403, 404, 500 use the standard error envelope.
curl -X POST "https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/$JOB_ID/cancel" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY"const jobId = "<jobId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/${jobId}/cancel`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
},
});
const { data, error, request_id } = await response.json();import os
import requests
job_id = "<jobId>"
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/{job_id}/cancel",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
)
payload = response.json(){
"data": {
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"project_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"speaker_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"source_voice_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"materialization_kind": "provider_asset",
"provider": "inworld",
"model": "string",
"selection_mode": "automatic",
"requested_candidate_count": 1,
"status": "queued",
"selection_expires_at": "2026-09-30T17:00:00.000Z",
"selected_candidate_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"cancel_requested_at": "2026-09-30T17:00:00.000Z",
"output_voice_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"output_provider_asset_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"assignment_outcome": "not_applicable",
"error_code": "string",
"error_message": "string",
"created_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"candidates": [
{
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"candidate_index": 1,
"preview_url": "https://lyricwinter.com/…",
"preview_text": "string",
"duration_ms": 1,
"status": "available"
}
]
},
"request_id": "req_01J9Z3K8QF4"
}Select a character voice candidate
POST/studio/voice-materialization-jobs/{jobId}/selection
studio:writeChoose one exact candidate from its original job before selection expires. The server checks candidate ownership and speaker authority; finalization can be asynchronous. Return the actual assignment outcome, and read the same job after uncertainty. No speech generation is started.
Path parameters
jobIdstringrequireduuid
Request body application/json
schema_version1requiredcandidate_idstringrequireduuid
Response 200
The selected voice was already finalized. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Response 202
Candidate finalization accepted. Fields below are inside data.
idstringrequireduuidproject_idstringrequireduuidsection_idstring | nullrequireduuidspeaker_idstring | nullrequireduuidsource_voice_idstring | nullrequireduuidmaterialization_kindanyrequiredOne of
provider_assetai_voice_creationprovideranyrequiredOne of
inworldcartesiafish_audiosmallest_aielevenlabsphononmodelstringrequiredmin 1 charsselection_modeanyrequiredOne of
automaticmanualrequested_candidate_countintegerrequired1–3statusanyrequiredOne of
queuedrunningawaiting_selectioncompletedfailedcancelledselection_expires_atstring | nullrequiredselected_candidate_idstring | nullrequireduuidcancel_requested_atstring | nullrequiredoutput_voice_idstring | nullrequireduuidoutput_provider_asset_idstring | nullrequireduuidassignment_outcomeanyrequiredOne of
not_applicableassignedspeaker_changederror_codestring | nullrequirederror_messagestring | nullrequiredcreated_atstringrequiredcompleted_atstring | nullrequiredcandidatesarray of objectrequiredmax 3 items6 item attributes
idstringrequireduuidcandidate_indexintegerrequired0–2preview_urlstring | nullrequireduripreview_textstringrequired1–500 charsduration_msinteger | nullrequired≥ 0statusanyrequiredOne of
availableselectedfinalizeddiscarded
Errors 400, 401, 403, 404, 409, 500 use the standard error envelope.
curl -X POST "https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/$JOB_ID/selection" \
-H "Authorization: Bearer $LYRICWINTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"schema_version": 1,
"candidate_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10"
}'const jobId = "<jobId>";
const response = await fetch(`https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/${jobId}/selection`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LYRICWINTER_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"schema_version": 1,
"candidate_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10"
}),
});
const { data, error, request_id } = await response.json();import os
import requests
job_id = "<jobId>"
response = requests.request(
"POST",
f"https://lyricwinter.com/api/v1/studio/voice-materialization-jobs/{job_id}/selection",
headers={
"Authorization": f"Bearer {os.environ['LYRICWINTER_API_KEY']}",
},
json={
"schema_version": 1,
"candidate_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10"
},
)
payload = response.json(){
"data": {
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"project_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"section_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"speaker_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"source_voice_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"materialization_kind": "provider_asset",
"provider": "inworld",
"model": "string",
"selection_mode": "automatic",
"requested_candidate_count": 1,
"status": "queued",
"selection_expires_at": "2026-09-30T17:00:00.000Z",
"selected_candidate_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
"cancel_requested_at": "2026-09-30T17:00:00.000Z",
"output_voice_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
"output_provider_asset_id": "d3d94468-02a4-4c5e-b6f7-0a1b2c3d4e40",
"assignment_outcome": "not_applicable",
"error_code": "string",
"error_message": "string",
"created_at": "2026-09-30T17:00:00.000Z",
"completed_at": "2026-09-30T17:00:00.000Z",
"candidates": [
{
"id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
"candidate_index": 1,
"preview_url": "https://lyricwinter.com/…",
"preview_text": "string",
"duration_ms": 1,
"status": "available"
}
]
},
"request_id": "req_01J9Z3K8QF4"
}