Skip to content

API reference

Voices and uploads API

Discover accessible voices, inspect current engine eligibility, and upload a private voice through the ordinary asynchronous upload flow. Retain original voice, resource and operation identifiers when recovering an interrupted upload.

BetaUpdated

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

Discover accessible voices

GET/voices

Scope voices:read

Browse or search completed selectable voices in scope=mine, shared, or library. Library discovery works anonymously; private collections require voices:read. To receive pagination, send include_pagination=true with an explicit scope, without mine=true or sort=popular. Follow pagination.next_offset with the same scope, query and limit even when voices is empty: access or selectability filtering can remove rows after the page boundary. next_offset=null ends the result. Without this option, the existing voices-only payload is unchanged. context_project_id applies current Studio project authority and relevance. Results reflect current access and may change between reads; engine eligibility is checked separately.

Query parameters

  • qstringdefault ""

    Search text matched against voice name, description, tags, and the hybrid voice search RPC. Empty or omitted returns browse results.

  • limitinteger1–50default 20

    Maximum number of public/search results. Omitted means 20.

  • offsetinteger≥ 0default 0

    Non-negative integer offset. Omitted means 0.

  • minebooleandefault false

    When true, returns only the authenticated caller's voices. Anonymous callers receive an empty list.

  • include_minebooleandefault true

    When false, authenticated non-mine browse/search results omit the caller's owned voices. Only exact true/false strings are accepted.

  • scopestring

    Limits results to the caller's own voices, voices shared with the caller, or the public voice library.

    One ofminesharedlibrary

  • include_paginationbooleandefault false

    Opt in to raw-page continuation. Requires explicit scope=mine, shared or library; cannot combine with mine=true or sort=popular. Follow pagination.next_offset even on an empty filtered page. Omitted or false preserves the legacy voices-only payload.

  • context_project_idstringuuid

    Authenticated Studio project UUID. When present, owned AI-designed voices are limited to voices created for or actively used by this standalone or named project; omit it to request the full account catalog.

  • sortstring

    Only the exact value popular changes behavior. Other values currently fall through to the normal list/search path.

Response 200

Processed voice picker results. Fields below are inside data.

  • voicesarray of objectrequired
    17 item attributes
    • idstringrequireduuid
    • acoustic_revisioninteger≥ 1

      Stable logical voice acoustic revision. It increments when a reroll publishes new voice acoustics.

    • namestringrequired
    • descriptionstring | nullrequired
    • tagsarray of stringrequired
    • statusstringrequired
    • available_modelsarray of stringrequired
    • default_modelstring | nullrequired
    • is_selectablebooleanrequired

      True when the voice is completed and has at least one available generation model.

    • is_user_createdbooleanrequired

      True when the resolved authenticated user owns the voice.

    • is_publicbooleanrequired
    • is_shared_with_userbooleanrequired

      True when an authenticated caller can access the voice through a share and does not own it.

    • voice_originstring | nullrequired
    • design_providerstring | nullrequired
    • sample_resource_versionstring | nullrequired

      Current sample resource version token, when a sample resource is available.

    • creator_usernamestring | nullrequired

      Creator username for public or accepted-shared voices; null for private owned voices or profiles without a username.

    • creator_display_namestring | nullrequired

      Creator profile display name for public or accepted-shared voices, used when no username exists.

  • paginationobject
    2 child attributes
    • next_offsetinteger | nullrequired≥ 0
    • has_morebooleanrequired

Errors 400, 401, 500 use the standard error envelope.

curl "https://lyricwinter.com/api/v1/voices" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
Response 200 (example)
{
  "data": {
    "voices": [
      {
        "id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
        "acoustic_revision": 1,
        "name": "My integration",
        "description": "string",
        "tags": [
          "string"
        ],
        "status": "string",
        "available_models": [
          "string"
        ],
        "default_model": "string",
        "is_selectable": true,
        "is_user_created": true,
        "is_public": true,
        "is_shared_with_user": true,
        "voice_origin": "string",
        "design_provider": "string",
        "sample_resource_version": "string",
        "creator_username": "string",
        "creator_display_name": "string"
      }
    ],
    "pagination": {
      "next_offset": 1,
      "has_more": true
    }
  },
  "request_id": "req_01J9Z3K8QF4"
}

Initiate a voice upload

POST/voices

Scope voices:writeRetry with the same Idempotency-Key

Create a private voice upload with permission to use the recording. Send exact file metadata and an Idempotency-Key; retain that key, metadata, voiceId and resource identifiers. After a lost response, send the identical key/body with Idempotency-Recovery: only; this never creates a replacement. Allocation is saved atomically before signing. Recovery returns current status and fresh targets only while uploading; later statuses return an empty signedUrls array. Upload original bytes with the returned Content-Type to the issued targets, then complete that same voice. Changed input conflicts. Missing/expired keys fail closed; older started keys remain in-progress. Valid older completed receipts recover their original IDs and current status. Key retention is 24 hours; a known voice ID remains readable with GET /voices/{voiceId}. Unknown after expiry never proves that creation did nothing. Initiation is not a completed clone. Requires current voices:write.

Headers

  • Idempotency-Keystring8–128 charspattern ^[\x21-\x7E]+$

    Opaque client-generated key for retrying one intended mutation. Accepted values are 8-128 visible ASCII characters. Reusing the same key with the same authenticated principal, method, route, scope, and normalized body replays the stored terminal response; reusing it for a different request returns a 409 conflict.

  • Idempotency-Recoverystring

    Recovery-only lookup: requires the original Idempotency-Key and identical metadata. Never allocates a voice or resources; unavailable after the original 24-hour retention.

    One ofonly

Request body application/json

  • namestringrequired1–80 chars
  • descriptionstringrequired1–255 chars
  • tagsstring | array of stringrequired

    String inputs are comma-split by the service. Parsed tags must contain 1-20 entries, each 100 characters or fewer.

  • isPublicbooleanrequired

    Currently must be false; public voice publishing is disabled during initiation.

  • uploadTypestringrequiredmin 1 chars
  • filesarray of objectrequiredmin 1 items
    4 item attributes
    • filenamestringrequiredmin 1 chars
    • sizenumberrequired≥ 0

      Client-reported file size in bytes. AUDIO_SAMPLE_* files are rejected above 25 MiB by the service.

    • contentTypestring

      Content type used when signing the GCS write URL.

    • file_typestringrequiredmin 1 chars

      Current callers use values such as AUDIO_SAMPLE_WAV, AUDIO_SAMPLE_MP3, RVC_SAFETENSORS, and RVC_INDEX.

Response 201

Voice upload records and signed direct-upload URLs were created. Fields below are inside data.

  • successtruerequired
  • voiceIdstringrequireduuid
  • signedUrlsarray of objectrequired
    4 item attributes
    • resourceIdstringrequireduuid
    • signedUrlstringrequireduri

      Short-lived v4 signed GCS write URL. Current implementation signs for 15 minutes.

    • gcsPathstringrequired

      Quarantine bucket object path created for this resource.

    • contentTypestring

      Echoed content type when one was provided for signing.

  • messagestringrequired
  • statusstring

    Present on recovery-only responses and advanced replays. Upload targets are empty unless status is uploading; acceptance is not processing completion.

    One ofuploadingpendingprocessingcompletedfailed

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

curl -X POST "https://lyricwinter.com/api/v1/voices" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "My integration",
  "description": "string",
  "tags": "string",
  "isPublic": true,
  "uploadType": "string",
  "files": [
    {
      "filename": "string",
      "size": 0,
      "file_type": "string"
    }
  ]
}'
Response 201 (example)
{
  "data": {
    "success": true,
    "voiceId": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
    "signedUrls": [
      {
        "resourceId": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
        "signedUrl": "https://lyricwinter.com/…",
        "gcsPath": "string",
        "contentType": "string"
      }
    ],
    "message": "string",
    "status": "uploading"
  },
  "request_id": "req_01J9Z3K8QF4"
}

Read accessible voices by exact IDs

POST/voices/by-ids

Scope voices:read

Hydrate exact voice identifiers through current owned, shared and public access checks. Missing or inaccessible voices are not evidence of a different replacement voice. Use the returned IDs and current status rather than matching display names.

Request body application/json

  • idsarray of stringrequired1–100 items

Response 200

Processed voice picker results. Fields below are inside data.

  • voicesarray of objectrequired
    17 item attributes
    • idstringrequireduuid
    • acoustic_revisioninteger≥ 1

      Stable logical voice acoustic revision. It increments when a reroll publishes new voice acoustics.

    • namestringrequired
    • descriptionstring | nullrequired
    • tagsarray of stringrequired
    • statusstringrequired
    • available_modelsarray of stringrequired
    • default_modelstring | nullrequired
    • is_selectablebooleanrequired

      True when the voice is completed and has at least one available generation model.

    • is_user_createdbooleanrequired

      True when the resolved authenticated user owns the voice.

    • is_publicbooleanrequired
    • is_shared_with_userbooleanrequired

      True when an authenticated caller can access the voice through a share and does not own it.

    • voice_originstring | nullrequired
    • design_providerstring | nullrequired
    • sample_resource_versionstring | nullrequired

      Current sample resource version token, when a sample resource is available.

    • creator_usernamestring | nullrequired

      Creator username for public or accepted-shared voices; null for private owned voices or profiles without a username.

    • creator_display_namestring | nullrequired

      Creator profile display name for public or accepted-shared voices, used when no username exists.

  • paginationobject
    2 child attributes
    • next_offsetinteger | nullrequired≥ 0
    • has_morebooleanrequired

Errors 400, 401, 500 use the standard error envelope.

curl -X POST "https://lyricwinter.com/api/v1/voices/by-ids" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "ids": [
    "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10"
  ]
}'
Response 200 (example)
{
  "data": {
    "voices": [
      {
        "id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
        "acoustic_revision": 1,
        "name": "My integration",
        "description": "string",
        "tags": [
          "string"
        ],
        "status": "string",
        "available_models": [
          "string"
        ],
        "default_model": "string",
        "is_selectable": true,
        "is_user_created": true,
        "is_public": true,
        "is_shared_with_user": true,
        "voice_origin": "string",
        "design_provider": "string",
        "sample_resource_version": "string",
        "creator_username": "string",
        "creator_display_name": "string"
      }
    ],
    "pagination": {
      "next_offset": 1,
      "has_more": true
    }
  },
  "request_id": "req_01J9Z3K8QF4"
}

Read voice processing status

GET/voices/{voiceId}

Scope voices:read

Read the accessible original voice's current status and acoustic revision. Upload completion can return while processing is pending; poll this read rather than initiating another upload. Completed processing and current engine eligibility are separate checks.

Path parameters

  • voiceIdstringrequireduuid

Response 200

Managed voice details and caller admin status. Fields below are inside data.

  • voiceobjectrequired
    23 child attributes
    • idstringrequireduuid
    • acoustic_revisionintegerrequired≥ 1
    • namestringrequired
    • descriptionstring | nullrequired
    • tagsarray of stringrequired
    • is_publicbooleanrequired
    • created_atstringrequireddate-time
    • updated_atstringrequireddate-time
    • statusstringrequired
    • error_messagestring | null
    • voice_originstring | null
    • design_providerstring | null
    • public_visibility_lockedboolean | null
    • public_visibility_locked_atstring | nulldate-time
    • public_visibility_lock_reasonstring | null
    • is_shared_with_userboolean
    • creator_usernamestring | nullrequired
    • creator_display_namestring | nullrequired
    • can_update_metadatabooleanrequired
    • can_deletebooleanrequired
    • can_rerollbooleanrequired
    • can_replace_samplefalserequired

      Reserved for a future same-ID sample replacement contract; v1 does not support that operation.

    • resourcesarray of object | null
      8 item attributes
      • idstring | nulluuid
      • acoustic_revisioninteger | null≥ 1
      • resource_typestring | null
      • gcs_pathstring | null
      • metadataobject | null
      • created_atstring | nulldate-time
      • statusstring | null
      • error_messagestring | null
  • isAdminbooleanrequired

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

curl "https://lyricwinter.com/api/v1/voices/$VOICE_ID" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
Response 200 (example)
{
  "data": {
    "voice": {
      "id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
      "acoustic_revision": 1,
      "name": "My integration",
      "description": "string",
      "tags": [
        "string"
      ],
      "is_public": true,
      "created_at": "2026-09-30T17:00:00.000Z",
      "updated_at": "2026-09-30T17:00:00.000Z",
      "status": "string",
      "error_message": "string",
      "voice_origin": "string",
      "design_provider": "string",
      "public_visibility_locked": true,
      "public_visibility_locked_at": "2026-09-30T17:00:00.000Z",
      "public_visibility_lock_reason": "string",
      "is_shared_with_user": true,
      "creator_username": "string",
      "creator_display_name": "string",
      "can_update_metadata": true,
      "can_delete": true,
      "can_reroll": true,
      "can_replace_sample": false,
      "resources": [
        {
          "id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
          "acoustic_revision": 1,
          "resource_type": "string",
          "gcs_path": "string",
          "metadata": {},
          "created_at": "2026-09-30T17:00:00.000Z",
          "status": "string",
          "error_message": "string"
        }
      ]
    },
    "isAdmin": true
  },
  "request_id": "req_01J9Z3K8QF4"
}

Read current voice engine options

GET/voices/{voiceId}/engine-samples

Scope voices:read

Read current-account engine availability, preparation requirements, reasons, acoustic revision and existing samples for this exact voice. This read neither selects an engine nor generates a sample. Check the returned status and profile before casting or requesting generation; do not silently substitute another engine.

Path parameters

  • voiceIdstringrequireduuid

Response 200

Current voice engine sample catalog. Fields below are inside data.

  • schema_version1required
  • voice_idstringrequireduuid
  • acoustic_revisionintegerrequired≥ 1
  • canonical_textobjectrequired
    2 child attributes
    • version"voice-engine-sample-en-v1"required
    • text"At first light, Rowan whispered, "We made it," then laughed softly into the rain."required
  • default_modelstring | nullrequired
  • model_optionsarray of objectrequiredmax 50 items
    8 item attributes
    • providerstringrequired
    • modelstringrequired
    • labelstringrequired
    • availabilitystringrequired

      One ofreadypreparation_requiredunavailable

    • reasonstring | nullrequired
    • compiler_versionstringrequired
    • estimated_snowcoinsintegerrequired≥ 0
    • sampleobject | nullrequired
      18 child attributes
      • schema_version1required
      • sample_idstringrequireduuid
      • voice_idstringrequireduuid
      • acoustic_revisionintegerrequired≥ 1
      • providerstringrequired1–100 chars
      • modelstringrequired1–100 chars
      • canonical_text_versionstringrequired

        One ofvoice-engine-sample-en-v1voice-preview-line-v1

      • compiler_versionstringrequired1–200 chars
      • statusstringrequired

        One ofpreparing_voicequeuedrunningcompletedfailedexpired

      • cache_statusstring | nullrequired

        One ofmisscoalescedhit

      • estimated_snowcoinsintegerrequired≥ 0
      • charged_snowcoinsintegerrequired≥ 0
      • audio_urlstring | nullrequireduri
      • audio_url_expires_atstring | nullrequireddate-time
      • errorobject | nullrequired
        3 child attributes
        • codestringrequired1–120 chars
        • messagestringrequired1–500 chars
        • retryablebooleanrequired
      • created_atstringrequireddate-time
      • updated_atstringrequireddate-time
      • expires_atstringrequireddate-time

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

curl "https://lyricwinter.com/api/v1/voices/$VOICE_ID/engine-samples" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
Response 200 (example)
{
  "data": {
    "schema_version": 1,
    "voice_id": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
    "acoustic_revision": 1,
    "canonical_text": {
      "version": "voice-engine-sample-en-v1",
      "text": "At first light, Rowan whispered, \"We made it,\" then laughed softly into the rain."
    },
    "default_model": "string",
    "model_options": [
      {
        "provider": "string",
        "model": "string",
        "label": "string",
        "availability": "ready",
        "reason": "string",
        "compiler_version": "string",
        "estimated_snowcoins": 1,
        "sample": {
          "schema_version": 1,
          "sample_id": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
          "voice_id": "45c48cce-2e2d-4fbd-8a1c-5e6f7a8b9c30",
          "acoustic_revision": 1,
          "provider": "string",
          "model": "string",
          "canonical_text_version": "voice-engine-sample-en-v1",
          "compiler_version": "string",
          "status": "preparing_voice",
          "cache_status": "miss",
          "estimated_snowcoins": 1,
          "charged_snowcoins": 1,
          "audio_url": "https://lyricwinter.com/…",
          "audio_url_expires_at": "2026-09-30T17:00:00.000Z",
          "error": {
            "code": "string",
            "message": "string",
            "retryable": true
          },
          "created_at": "2026-09-30T17:00:00.000Z",
          "updated_at": "2026-09-30T17:00:00.000Z",
          "expires_at": "2026-09-30T17:00:00.000Z"
        }
      }
    ]
  },
  "request_id": "req_01J9Z3K8QF4"
}

Refresh original upload targets

POST/voices/{voiceId}/uploads/refresh

Scope voices:write

Renew expiring upload targets for the same uploading voice and original resources. This does not create a replacement voice. Keep the original identifiers and upload only to the newly returned targets. Requires voices:write and authority over the upload.

Path parameters

  • voiceIdstringrequireduuid

Response 200

Voice upload records and signed direct-upload URLs were created. Fields below are inside data.

  • successtruerequired
  • voiceIdstringrequireduuid
  • signedUrlsarray of objectrequired
    4 item attributes
    • resourceIdstringrequireduuid
    • signedUrlstringrequireduri

      Short-lived v4 signed GCS write URL. Current implementation signs for 15 minutes.

    • gcsPathstringrequired

      Quarantine bucket object path created for this resource.

    • contentTypestring

      Echoed content type when one was provided for signing.

  • messagestringrequired
  • statusstring

    Present on recovery-only responses and advanced replays. Upload targets are empty unless status is uploading; acceptance is not processing completion.

    One ofuploadingpendingprocessingcompletedfailed

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

curl -X POST "https://lyricwinter.com/api/v1/voices/$VOICE_ID/uploads/refresh" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY"
Response 200 (example)
{
  "data": {
    "success": true,
    "voiceId": "8f14e45f-ceea-4e7a-9c2d-3b1a5f2e7c10",
    "signedUrls": [
      {
        "resourceId": "c9f0f895-fb98-4b91-9e3f-1d2a6b7c8d20",
        "signedUrl": "https://lyricwinter.com/…",
        "gcsPath": "string",
        "contentType": "string"
      }
    ],
    "message": "string",
    "status": "uploading"
  },
  "request_id": "req_01J9Z3K8QF4"
}

Complete the original voice upload

POST/voices/{voiceId}/uploads/complete

Scope voices:writeRetry with the same Idempotency-Key

Finalize the existing voice after its files have been uploaded. Use an Idempotency-Key and retain it together with the original voice ID on uncertainty; retry only that same completion. Acceptance starts or recovers asynchronous processing and does not mean the clone is ready. Read the voice's current status and engine options before use. Requires voices:write.

Path parameters

  • voiceIdstringrequireduuid

Headers

  • Idempotency-Keystring8–128 charspattern ^[\x21-\x7E]+$

    Opaque client-generated key for retrying one intended mutation. Accepted values are 8-128 visible ASCII characters. Reusing the same key with the same authenticated principal, method, route, scope, and normalized body replays the stored terminal response; reusing it for a different request returns a 409 conflict.

Response 202

Voice upload finalization was accepted and background processing was scheduled. Fields below are inside data.

  • successtruerequired
  • messagestringrequired

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

curl -X POST "https://lyricwinter.com/api/v1/voices/$VOICE_ID/uploads/complete" \
  -H "Authorization: Bearer $LYRICWINTER_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
Response 202 (example)
{
  "data": {
    "success": true,
    "message": "string"
  },
  "request_id": "req_01J9Z3K8QF4"
}