# Authentication Source: https://wiz-myvocal.mintlify.app/api-reference/authentication Authenticate with MyVocal APIs using the accessKey header. ## How authentication works MyVocal API uses a single header for authentication on every endpoint: ```http theme={null} accessKey: ``` ## Where to get your API key 1. Sign in to [MyVocal Account](https://www.myvocal.ai/account). 2. Open Account Info. 3. Copy your API key. ## Header format API key used to authenticate your request. ## Security best practices * Keep API keys on your backend server. * Do not expose API keys in frontend code or mobile apps. * Do not commit API keys to Git repositories. * Rotate key immediately if you suspect leakage. ## Example request ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/user/info' \ --header 'accessKey: ' ``` ## Text-to-Music and Interpretation Text-to-Music (`/sound_clone/api/v1/music`) and Interpretation (`/sound_clone/api/v1/interpretation`) use the same `accessKey` header, the same public host and the same API-key account as every other endpoint on this page. There is no separate key, scope, host or login for them. They do **not** require a cloned voice and do **not** require a browser/workspace session. The account that owns the key is always the owner of the resources it creates: no request body, path or query parameter can select a different owner. Requesting a resource you do not own and requesting one that does not exist return the same not-found error, so the API never reveals whether an identifier exists. Three differences from the synchronous endpoints are worth remembering: * Both products are **asynchronous**: they return a project/job identifier immediately and you poll for the result. See [Async jobs, polling and retries](/guides/async-jobs-and-retries). * The `Idempotency-Key` header is **required** on the create/accept endpoints. Use a unique printable ASCII value of 16–64 characters per distinct operation. Replaying the same key with the same body is safe; replaying it with a different body is a conflict. * Credits are measured in **Characters** and are quoted before they are spent. See [Characters, quotes and billing](/guides/characters-and-quotes). Brief → arrangement → quote → generate → play/download. Upload → probe → quote → generate → play → export/download. ## Speech to Text Batch and Real-time STT use the same `accessKey` under `https://api.myvocal.ai/sound_clone/api/v1/stt`. No new key, cloned voice or workspace login is required. The key determines the owner of uploads, transcriptions and sessions. Use `Idempotency-Key` for Batch submission and real-time session creation, with a fresh key per logical task and the same key/body for a retry. Server WebSocket clients can send `accessKey` as a handshake header. Browser clients use [one-use tickets](/api-reference/stt/createTicket); keep the long-lived API key on your backend in a customer-facing application. See [Batch](/guides/stt-batch-quickstart), [Real-time](/guides/stt-realtime-quickstart) and [current limitations](/guides/stt-availability). ## Accent model requests The Accent model (`myvocal_v3_accent_enhance`) reuses everything on this page: the same `accessKey` header, the same API host and the same TTS endpoints. There is no separate key, scope or endpoint to request, and no extra header to send. Public model IDs and how the default path, `myvocal_v3` and the Accent model differ. Get a compatible `voiceId` with `modelId=myvocal_v3_accent_enhance`. Authentication, voice discovery, synthesis and history in one flow. # Generate a cover Source: https://wiz-myvocal.mintlify.app/api-reference/cover/cover POST https://api.myvocal.ai/sound_clone/api/v1/cover Submit a song file and a Cover voice to create an AI cover. The result is delivered to your callback URL. **AI Cover** · Workflow: [AI Cover quickstart](/guides/cover-quickstart) The finished cover is delivered to your `callbackUrl`; see [Cover callbacks](/callback) (`COVER_SONG`). Generated covers are listed in [Cover History](/api-reference/history/coverList). ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Your custom voice's id or premade voice's id. Please do not exceed 32 characters in length.If it is empty, the first 32 characters of target\_song will be used as the title.

The target song you want to generate cover version.

Please upload mp3/wav files and do not exceed 50MB.

To receive the audio returned after processing is completed. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. When the request is successfully sent, a webhookId will be synchronously returned. The same information will also be called back in the callbackUrl, which is used to correlate the request and the response. ```bash Example Request theme={null} curl --location --request POST 'https://api.myvocal.ai/sound_clone/api/v1/cover' \ --header 'accessKey: xxx' \ --form 'files=@"xxx/xxx.mp3"' \ --form 'voiceId="111"' \ --form 'title="test"' \ --form 'callbackUrl="http://www.google.com"' ``` ```json 200(success) theme={null} # success { "code": 1, "message": "Success", "data": { "webhookId": "7812" } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # List Cover history Source: https://wiz-myvocal.mintlify.app/api-reference/history/coverList GET https://api.myvocal.ai/sound_clone/sound_clone/api/v1/cover/list List your AI Cover history records, with a cursor for older records. **AI Cover · History** · Workflow: [AI Cover quickstart](/guides/cover-quickstart) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body
The number of AI Cover history records returned at one time, supporting 10 \~ 1000 data queries at a time.
If this parameter is empty, the default value is 10.
If this parameter is provided, we will start tracing back to earlier AI Cover history from this AI Cover item.
If this parameter is empty, then we will default to tracing back directly from the most recent data.
### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data.
If there is no earlier created AI Cover item, then callback 1
If there are still earlier created AI Cover items, then callback 0
The earliest AI Cover id in this response. The AI Cover history records returned by this request. AI Cover id AI Cover title character count of this AI Cover item. web or api The voiceId of the voice used to generate this AI Cover The voice name of the voice used to generate this AI Cover.
```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/cover/list' \ --header 'accessKey: xxx' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": { "hasMore": false, "earliestHistoryItemId": "198", "list": [ { "voiceId": "458", "voiceName": "QWERTYUIOPASD", "id": "203", "title": "Beyonce T4", "useChars": 2616, "channel": "web" }, { "voiceId": "452", "voiceName": "@#$%^&Z", "id": "202", "title": "sd", "useChars": 2592, "channel": "api" } ] } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Get Cover audio URLs Source: https://wiz-myvocal.mintlify.app/api-reference/history/coverListUrl POST https://api.myvocal.ai/sound_clone/api/v1/cover/query Get playable audio URLs for up to 1,000 AI Cover history records. **AI Cover · History** · Workflow: [AI Cover quickstart](/guides/cover-quickstart) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body You can provide up to 1,000 Ids at a time. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Your AI Cover id. The audio file URL for that AI Cover id. ```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/cover/query' \ --header 'accessKey: xxx' \ --header 'Content-Type: application/json' \ --data '{ "ids":["22","13"] }' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": [ { "id": "2195", "url": "xxxx" }, { "id": "2196", "url": "xxxx" } ] } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Delete Cover history Source: https://wiz-myvocal.mintlify.app/api-reference/history/deleteCover DELETE https://api.myvocal.ai/sound_clone/api/v1/cover Delete up to 500 AI Cover history records in one request by AI Cover ID. **AI Cover · History** · Workflow: [AI Cover quickstart](/guides/cover-quickstart) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body You can provide up to 500 Ids at a time. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. Ids included are deleted successfully. Ids included do not exist. Ids included do not belong to this feature. ```bash Example Request theme={null} curl --location --request DELETE 'https://api.myvocal.ai/sound_clone/api/v1/cover' \ --header 'accessKey: xxx' \ --header 'Content-Type: application/json' \ --data '{ "ids":["2196","2195"] }' ``` ```json 200(success) theme={null} # success { "code": 1, "message": "Success", "data": { "succeedIds": [], "nonExistIds": [], "unMatchIds": [ "203" ] } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Delete TTS history Source: https://wiz-myvocal.mintlify.app/api-reference/history/deleteTTS DELETE https://api.myvocal.ai/sound_clone/api/v1/tts Delete up to 500 Text to Speech history records in one request by TTS ID. **Text to Speech · History** · Workflow: [TTS quickstart](/quickstart#step-7-query-history-and-output-urls) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body You can provide up to 500 Ids at a time. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. Ids included are deleted successfully. Ids included do not exist. Ids inclueded do not belong to this feature. ```bash Example Request theme={null} curl --location --request DELETE 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: xxx' \ --header 'Content-Type: application/json' \ --data '{ "ids":["2196","2195"] }' ``` ```json 200(success) theme={null} # success { "code": 1, "message": "Success", "data": { "succeedIds": [], "nonExistIds": [], "unMatchIds": [ "219623" ] } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # List TTS history Source: https://wiz-myvocal.mintlify.app/api-reference/history/ttsList GET https://api.myvocal.ai/sound_clone/api/v1/tts/list List your Text to Speech history records, with a cursor for older records. **Text to Speech · History** · Workflow: [TTS quickstart](/quickstart#step-7-query-history-and-output-urls) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body
The number of TTS History queries at one time, supporting 10 \~ 1000 data queries at a time.
If this parameter is empty, the default value is 10.
If this parameter is provided, we will start tracing back to earlier TTS History from this TTS item.
If this parameter is empty, then we will default to tracing back directly from the most recent data.
### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data.
If there is no earlier created TTS item, then callback 1
If there are still earlier created TTS items, then callback 0
The earliest ttsid in this callback. The specific info of TTS history queried this time. tts id tts title tts content character count of this TTS item. chosen language web or api The voiceid of the voice used to generate this TTS TThe voicename of the voice used to generate this TTS.
```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/list' \ --header 'accessKey: xxx' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": { "hasMore": true, "earliestHistoryItemId": "2186", "list": [ { "voiceId": "7813", "voiceName": "test", "id": "2197", "title": "female", "text": "Generate a text-to-speech audio using a voice of your choice and returns audio stream.", "useChars": 86, "language": "en", "channel": "api" }, { "voiceId": "7789", "voiceName": "FirstClonedVoice", "id": "2194", "title": "female", "text": "Generate a text-to-speech audio using a voice of your choice and returns audio stream.", "useChars": 86, "language": "en", "channel": "api" } ] } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Get TTS audio URLs Source: https://wiz-myvocal.mintlify.app/api-reference/history/ttsListUrl POST https://api.myvocal.ai/sound_clone/api/v1/tts/query Get playable audio URLs for up to 1,000 Text to Speech history records. **Text to Speech · History** · Workflow: [TTS quickstart](/quickstart#step-7-query-history-and-output-urls) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body You can provide up to 1,000 Ids at a time. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Your tts id. The audio file url corresponding to ttsId. ```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/query' \ --header 'accessKey: xxx' \ --header 'Content-Type: application/json' \ --data '{ "ids":["22","13"] }' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": [ { "id": "2195", "url": "xxxx" }, { "id": "2196", "url": "xxxx" } ] } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Interpretation capabilities Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/capabilities GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/capabilities Read the Interpretation account state, rate, language catalog and supported formats. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Read this endpoint first. It publishes the language keys you may request, the accepted input formats, the export formats and the account's rate — instead of hard-coding any of them. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response The product name, `Interpretation`. Version label of the applicable rate. Version of the language catalog. `CONFIGURED` when an authoritative language list is configured; `EMPTY` when no usable entries exist, in which case quoting is not available. Version of the accepted-format catalog. The language entries: `{ languageKey, displayName, sourceSupport }`. Use `languageKey` as `targetLanguages` and `sourceLanguage`. Accepted audio containers/extensions. Accepted video containers/extensions. `mp3`, `wav`, `flac`, `mp4`. `mp4` is the composed video and requires a video source. Maximum declared upload size, as a **string**. Convert before comparing. `{ planKey, charactersPerMinutePerLanguage }` entries. How long a quote stays valid. Currently `600`. `{ planKey, accessState, entitlementVersion, charactersPerMinutePerLanguage, availableCharacters, balanceState }`. `availableCharacters` is a **string** or `null`. * `accessState` is one of `ENABLED`, `FREE_LOCKED`, `ENTERPRISE_UNRESOLVED`, `SYNCING` or `UNRESOLVED`. Only `ENABLED` may generate. * `balanceState` is either `AVAILABLE` or `LEDGER_UNAVAILABLE`, and it describes **this** account field only. When the shared ledger read is unavailable, `availableCharacters` is `null` and `balanceState` is `LEDGER_UNAVAILABLE` instead of a guessed number. Availability flags for the public stages. Internal development identifiers are not published here. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/capabilities' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "productName": "Interpretation", "rateVersion": "interp-2026-09-27-v1", "languageCatalogVersion": "1", "languageCatalogState": "CONFIGURED", "formatCatalogVersion": "1", "languages": [ { "languageKey": "es", "displayName": "Spanish", "sourceSupport": "UNVERIFIED" }, { "languageKey": "fr", "displayName": "French", "sourceSupport": "UNVERIFIED" } ], "audioFormats": ["mp3", "wav", "m4a", "aac", "flac", "aiff", "ogg", "oga", "opus", "weba"], "videoFormats": ["mp4", "mov", "m4v", "mkv", "avi", "webm", "wmv", "mpeg", "mpg", "3gpp"], "exportFormats": ["mp3", "wav", "flac", "mp4"], "maxSourceBytes": "3221225472", "planRates": [ { "planKey": "PRO", "charactersPerMinutePerLanguage": 4000 } ], "quoteTtlSeconds": 600, "account": { "planKey": "PRO", "accessState": "ENABLED", "entitlementVersion": "1", "charactersPerMinutePerLanguage": 4000, "availableCharacters": "10500", "balanceState": "AVAILABLE" }, "stageAvailability": { "project": "AVAILABLE", "upload": "AVAILABLE", "export": "AVAILABLE" }, "requestId": "..." } } ``` ### Common errors * `code = 401`, `"Key verification failed"`: the `accessKey` is missing, invalid or disabled. Returned with HTTP `200` and **no** `data`. * `code = 47128`: the account's plan is not entitled to generate (for example `FREE`). * `code = 47119`: an ENTERPRISE account has no configured contract rate. Interpretation does **not** fall back to a default rate. # Complete an upload Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/completeUpload POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/{uploadId}/complete Assemble the uploaded parts, probe the media and commit the source version. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Tells the service that all parts are uploaded. It assembles the object, probes the media, and publishes the source version. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The upload session identifier. ### Body **All** parts, in part-number order: `{ partNumber, etag }`, using the exact `ETag` values returned by object storage. Missing, extra or mismatched entries are rejected with `47126`. ### Response The upload session. Project identifier. `READY` when the probe has already finished; otherwise `COMPLETING` or `PROBING`, so poll `GET /uploads/{uploadId}`. Set when the upload failed. The created source asset, or `null` when it has not been created yet. The committed source version. Detected duration, as a **string**. `{ inputFormat, containerName, audioStreamCount, video, width, height, rotationDegrees }`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/iu_.../complete' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "parts": [ { "partNumber": 1, "etag": "" }, { "partNumber": 2, "etag": "" } ] }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "uploadId": "iu_...", "projectId": "ip_...", "state": "READY", "errorCode": null, "sourceAssetId": "ia_...", "sourceVersion": 1, "durationMs": "90000", "media": { "inputFormat": "mov,mp4,m4a,3gp,3g2,mj2", "containerName": "mov,mp4,m4a,3gp,3g2,mj2", "audioStreamCount": 1, "video": true }, "requestId": "..." } } ``` Retrying completion is safe: the service tolerates a lost response by re-reading the object metadata. But always send the **complete** part list — not just the last part. ### Common errors * `code = 47126`: the submitted part list does not match the session. * `code = 47124`: the upload session does not exist or is not owned by your account. * `code = 47125`: the file exceeded the size limit or had no content. * `code = 47104` / `47105`: the source is invalid or has no audio track. * `code = 47127`: object storage is unavailable — retry. # Create an export Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/createExport POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/targets/{targetId}/exports Start a downloadable export of one finished target language. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Starts an asynchronous export of a ready target language in the requested format. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The target language entry. It must be ready and have an output asset. ### Body One of `capabilities.exportFormats`: `mp3`, `wav`, `flac` or `mp4`. `mp4` is the composed video and requires a video source. ### Response The export identifier. Poll the download endpoint with this same id. The target language. The requested format. `PROCESSING` at first. Later `RETRY` (a transient retry of the same export) or `READY`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/targets/it_.../exports' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "format": "wav" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "exportId": "ie_...", "targetId": "it_...", "format": "wav", "state": "PROCESSING", "requestId": "..." } } ``` `PROCESSING` and `RETRY` are not failures: keep polling the **same** `exportId`. Starting a new generation to work around a slow export will charge again. ### Common errors * `code = 47117`: the target does not exist, is not part of a project you own, or is not ready. * `code = 47101`: `format` is missing or is not a supported export format. * `code = 47102`: the project does not exist **or** is not owned by your account. # Accept an interpretation quote Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/createGeneration POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/generations Accept a quote and start generating the translated target languages. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Accepts the quote, reserves its Characters per language and queues the work. The call returns immediately; poll the project or the jobs for progress. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per operation: 16–64 printable ASCII characters. Same key with a different body is rejected with `47111`. ### Path The project identifier. ### Body The quote to accept. Must not be `null` — see `ALL_TARGETS_EXIST` in the quote endpoint. ### Response Stable identifier of the accepted generation. Use it (or the target/job IDs) to recover. Alias of `acceptanceId`. Project identifier. The accepted quote. Acceptance state, for example `ACCEPTED`. `{ targetId, language, generationId, state, jobId, reservationCycle, reservedCharacters }`. `reservedCharacters` is a **string**. Languages that already existed and were not charged again. Languages newly created by this acceptance. Total reserved Characters, as a **string**. Reservation cycle for this acceptance. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../generations' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 5ad0f3c7b21e4896' \ --data '{ "quoteId": "iq_..." }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "acceptanceId": "ia_...", "generationId": "ia_...", "projectId": "ip_...", "quoteId": "iq_...", "state": "ACCEPTED", "targets": [ { "targetId": "it_...", "language": "es", "generationId": "ia_...", "state": "QUEUED", "jobId": "ij_...", "reservationCycle": 1, "reservedCharacters": "6000" }, { "targetId": "it_...", "language": "fr", "generationId": "ia_...", "state": "QUEUED", "jobId": "ij_...", "reservationCycle": 1, "reservedCharacters": "6000" } ], "existingTargets": [], "newTargets": [ { "language": "es", "characters": "6000" }, { "language": "fr", "characters": "6000" } ], "reservedCharacters": "12000", "reservationCycle": 1, "requestId": "..." } } ``` Replays are not byte-for-byte copies of the first response, and there are two distinct behaviours: * **Same key, same body**: the existing acceptance is returned, re-read from the current state, so the target and job states may already have advanced. * **Same quote, a different key**: if the quote was already accepted, the existing acceptance is returned again **before any price re-check** and without charging twice. This is deliberate and differs from the Text-to-Music rule, where a consumed quote is rejected with `47007`. A **same key with a different body** is a real conflict (`47111`): re-read the project to discover what already happened instead of silently switching to a new key. ### Common errors * `code = 47111`: the `Idempotency-Key` was reused with a different body. * `code = 47110`: not enough Characters available. * `code = 47108` / `47109`: the quote expired or is no longer valid. * `code = 47103`: the source is not ready. * `code = 47119`: an ENTERPRISE account has no configured contract rate. * `code = 47128`: the plan is not entitled to generate. * `code = 47102`: the project does not exist **or** is not owned by your account. # Create an interpretation project Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/createProject POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects Create an Interpretation project. The project starts empty; upload a source next. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Creates an empty project whose state is `DRAFT`. It does not start any processing — you set the draft, then upload a source. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per operation: 16–64 printable ASCII characters. Same key with the same body replays safely; same key with a different body is rejected with `47111`. ### Body Project name: non-empty after trimming, at most 120 code points. Optional. `null`, an empty string or `AUTO` means automatic detection; otherwise a language key from `capabilities.languages`. Optional initial target languages. May be empty; the selection can be changed later with `PATCH /draft`. ### Response Stable project identifier. `DRAFT` right after creation. The current draft version. Pass it as `expectedVersion` / `settingsVersion` in later calls to detect concurrent changes. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 0d2b7c3a91f54b62' \ --data '{ "name": "Launch video ES/FR", "targetLanguages": ["es", "fr"] }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "ip_...", "state": "DRAFT", "settingsVersion": 1, "requestId": "..." } } ``` A replay re-reads the current project; the response may reflect later state than the first call. Keep `projectId` as the anchor. ### Common errors * `code = 47101`: the name is missing, empty or too long. * `code = 47111`: the `Idempotency-Key` was reused with a different body. * `code = 47122`: temporarily unavailable — retry with backoff. # Quote interpretation targets Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/createQuote POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/quotes Price the translation and dubbing of the requested target languages. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Quoting is free. The price is per **new** target language: adding a language to an existing project charges only for the language being added. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. The source must already be ready. ### Body Optional. If present and different from the current version, the request is rejected with `47109`. The languages to price. Must not be empty. ### Response Pass this to the generation endpoint. `null` when `state` is `ALL_TARGETS_EXIST`. Project identifier. Draft version the quote was based on. Source duration, as a **string**. The plan the rate came from. Rate version label. The rate applied, per language. Characters per new language, as a **string**. The languages you asked for. Languages that already exist for this source: `{ language, characters, targetId, state, action }`. Languages that will be created and charged. The languages a submission would create and reserve now. This field is **the same content as `newTargets`**, kept under its pre-decision name — it is **not** a union of `existingTargets` and `newTargets`, and it excludes languages the project already carries. Total charge, as a **string**. `"0"` for `ALL_TARGETS_EXIST`. Available balance, as a **string**. Projected balance, as a **string**. `AVAILABLE` or `LEDGER_UNAVAILABLE` for this response, or `null`. It describes the balance fields of **this** response only; a `LEDGER_UNAVAILABLE` value means `availableCharacters` and `estimatedRemainingCharacters` are `null` rather than guessed. `ACTIVE`, `ALL_TARGETS_EXIST` or `CHANGED`. When the quote expires (time to live `quoteTtlSeconds`, normally 600 seconds). ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../quotes' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "settingsVersion": 1, "targetLanguages": ["es", "fr"] }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "quoteId": "iq_...", "projectId": "ip_...", "settingsVersion": 1, "sourceDurationMs": "90000", "planKey": "PRO", "rateVersion": "interp-2026-09-27-v1", "charactersPerMinutePerLanguage": 4000, "perTargetCharacters": "6000", "requestedLanguages": ["es", "fr"], "existingTargets": [], "newTargets": [ { "language": "es", "characters": "6000" }, { "language": "fr", "characters": "6000" } ], "targets": [ { "language": "es", "characters": "6000" }, { "language": "fr", "characters": "6000" } ], "totalCharacters": "12000", "availableCharacters": "20000", "estimatedRemainingCharacters": "8000", "balanceState": "AVAILABLE", "state": "ACTIVE", "expiresAt": "2027-01-15T16:05:00", "requestId": "..." } } ``` ```json 200 All targets already exist theme={null} { "code": 1, "message": "success", "data": { "quoteId": null, "perTargetCharacters": null, "totalCharacters": "0", "state": "ALL_TARGETS_EXIST", "existingTargets": [ { "language": "es", "characters": "6000", "targetId": "it_...", "state": "READY", "action": "NONE" } ], "requestId": "..." } } ``` `ALL_TARGETS_EXIST` is a successful quote, not an error. `quoteId` is `null` and `totalCharacters` is `"0"` — read `existingTargets` and **never** call the generation endpoint with a `null` quoteId. All Characters values are JSON strings; convert them before comparing. ### Common errors * `code = 47101`: `targetLanguages` is missing or empty. * `code = 47109`: the quote is no longer valid for this settings version, or the version changed. * `code = 47108`: the quote has expired. * `code = 47103`: the source is not ready yet. * `code = 47119`: an ENTERPRISE account has no configured contract rate. * `code = 47128`: the plan is not entitled to generate. * `code = 47102`: the project does not exist **or** is not owned by your account. # Create an upload session Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/createUpload POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/uploads Start a multipart upload for the project's source audio or video file. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Creates a multipart upload session. The service returns the part size and part count; the actual bytes are uploaded directly to object storage. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body Original file name, non-empty, at most 512 characters. Exact byte length of the file. Greater than `0` and not greater than `capabilities.maxSourceBytes`. Optional. When omitted or blank the service uses `application/octet-stream`. At most 128 characters; CR/LF are rejected. ### Response The upload session identifier. Use it for signing parts, polling status and completing. Project identifier. `CREATED` right after creation. The declared size, as a **string**. The size of each part, as decided by the service. Use it as returned. The number of parts to upload. Use it as returned. When the session expires (24 hours by default). ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../uploads' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "filename": "launch.mp4", "size": 18432611, "contentType": "video/mp4" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "uploadId": "iu_...", "projectId": "ip_...", "state": "CREATED", "declaredSize": "18432611", "partSizeBytes": 16777216, "totalParts": 2, "expiresAt": "2027-01-16T15:52:11", "requestId": "..." } } ``` Do not assume a fixed 16 MiB part size or a fixed 3 GiB limit. Read `partSizeBytes` and `totalParts` from this response and `maxSourceBytes` from `capabilities`. ### Common errors * `code = 47125`: the file exceeded the size limit, or the declared size is not greater than zero / the request is empty. * `code = 47101`: `filename` is missing or too long, or `contentType` is invalid. * `code = 47102`: the project does not exist **or** is not owned by your account. * `code = 47127`: object storage is unavailable — retry. # Delete an interpretation project Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/deleteProject DELETE https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId} Delete an Interpretation project owned by your account. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Response A success envelope with no data payload. ```bash theme={null} curl --location --request DELETE 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": null, "requestId": "..." } ``` Deletion is scoped to your ownership. Deleting a project does not retroactively change what the ledger already settled, and it does not cancel work that is still reconciling. ### Common errors * `code = 47102`: the project does not exist **or** is not owned by your account. * `code = 47122`: temporarily unavailable — retry with backoff. # Remove the interpretation source Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/deleteSource DELETE https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/source Detach the uploaded source from a project and return to a draft. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Removes the committed source version so the project can be edited and re-uploaded. Returns the draft representation, the same shape as `PATCH /draft`. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Response Project identifier. The current draft version. The project state, normally back to `DRAFT`. The stored source language, or `null`. The stored keyterms. The stored cloning strength. The stored target languages. Source duration as a **string**. The source state after removal. ```bash theme={null} curl --location --request DELETE 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../source' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "ip_...", "settingsVersion": 3, "state": "DRAFT", "sourceLanguage": "en", "keyterms": ["MyVocal"], "cloningStrength": 7, "targetLanguages": ["es", "fr"], "sourceDurationMs": "0", "sourceState": "SUPERSEDED", "requestId": "..." } } ``` ### Common errors * `code = 47102`: the project does not exist **or** is not owned by your account. * `code = 47123`: the source cannot be removed in the current state. # Download an export Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/downloadExport GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/exports/{exportId}/download Poll an export and get a temporary download URL once it is ready. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) This endpoint both reports progress and, once the export is `READY`, returns the temporary download URL for the file. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The export identifier from the create-export call. ### Response The export identifier. The export format. `PROCESSING`, `RETRY` or `READY`. Only `READY` has a download URL. The media type, once available. The temporary download URL. `null` while the export is still being processed. When the URL stops working. `null` while processing. The stored asset version, or `null` — notably while the export is still processing. Whether the URL supports range requests. How many renewal attempts one failed request may use before the authorization error is surfaced. Currently `1`: renew once, then report the error instead of retrying without bound. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/exports/ie_.../download' \ --header 'accessKey: ' ``` ```json 200 Still processing theme={null} { "code": 1, "message": "success", "data": { "exportId": "ie_...", "format": "wav", "state": "PROCESSING", "mimeType": null, "url": null, "expiresAt": null, "assetVersion": null, "rangeSupported": false, "renewalAttemptLimit": 1, "requestId": "..." } } ``` ```json 200 Ready theme={null} { "code": 1, "message": "success", "data": { "exportId": "ie_...", "format": "wav", "state": "READY", "mimeType": "audio/wav", "url": "https:///...", "expiresAt": "2027-01-15T16:20:00", "assetVersion": "1", "rangeSupported": true, "renewalAttemptLimit": 1, "requestId": "..." } } ``` Poll the **same** `exportId` while the state is `PROCESSING` or `RETRY`. Neither is a terminal failure, and neither has a URL yet. Only when the state is `READY` should you download the bytes — and if the URL has expired by then, call this endpoint again for a fresh one. A non-empty `url` field is not by itself proof of success: check `state` and verify that the transfer actually produced media bytes. ### Common errors * `code = 47113`: the export is recovering; keep polling. * `code = 47117`: the export does not exist, or is not owned by your account. * `code = 47127`: object storage is unavailable — retry. # Get an interpretation job Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/getJob GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/jobs/{jobId} Read the progress of one interpretation job, and the job list from the project detail. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The job identifier. Jobs are also listed in `targets`/`jobs` of the project detail. ### Response Job identifier. Owning project. The target language this job belongs to, or `null` for a project-level job. The internal pipeline stage, for example `PREPARE_PROJECT`, `CREATE_LANGUAGE`, `POLL_TARGET`, `FETCH_AUDIO`, `EXPORT_AUDIO`, `COMPOSE_VIDEO` or `SETTLE`. `QUEUED`, `RUNNING`, `RETRY`, `RECONCILING`, `READY`, `FAILED` or `RELEASED`. Currently always `null`: the service does not publish a suggested poll interval yet. Handle `null` and use your own bounded interval. Set when the job failed. `SETTLED`, `RESERVED`, `RELEASED` or `UNPRICED`, derived from the reservation and the target state. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/jobs/ij_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "jobId": "ij_...", "projectId": "ip_...", "targetId": "it_...", "stage": "FETCH_AUDIO", "state": "RUNNING", "nextPollAfterMs": null, "errorCode": null, "billingState": "RESERVED", "requestId": "..." } } ``` `RECONCILING` means the outcome is still being determined. It is **not** a failure and **not** a release of the reservation. Only a real ledger `RELEASED` state may be described as released. ### Common errors * `code = 47117`: the job does not exist, or it exists but is not owned by your account. The API deliberately returns the same answer for both, so it never reveals whether a job id exists. # Get an interpretation project Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/getProject GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId} Read the full state of an Interpretation project: source, targets and jobs. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) This is the main polling endpoint for Interpretation. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Response Project identifier. Project name. Aggregate project state: `DRAFT`, `UPLOADING`, `PROBING`, `PROCESSING`, `PARTIAL_READY`, `READY`, `FAILED` or `DELETED`. Rolled-up state: `DRAFT`, `PROCESSING`, `PARTIAL_READY`, `READY` or `FAILED`. The source language, or `null` when it is auto-detected. Detected duration of the frozen source, as a **string**. Current draft version. Current keyterms. Current cloning strength (`0`–`10`), or `null` when unset. The languages currently selected on the draft. `{ version, state, sourceLanguage, durationMs, sourceAssetId, cloningStrength, keyterms, media, availableExportFormats }`. `state` is `DRAFT`, `FROZEN` or `SUPERSEDED`; `durationMs` is a **string**; `media` is `{ inputFormat, containerName, audioStreamCount, video, width, height, rotationDegrees }`. `{ targetId, language, state, characters, billingState, action, reservationCycle, outputAssetId }`. `characters` is a **string** or `null`; `outputAssetId` is present once the language is ready. `{ jobId, projectId, targetId, stage, state, nextPollAfterMs, errorCode, billingState }`. `nextPollAfterMs` is currently always `null`. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "ip_...", "name": "Launch video ES/FR", "state": "READY", "summaryState": "READY", "sourceLanguage": "en", "sourceDurationMs": "90000", "settingsVersion": 1, "draftTargetLanguages": ["es", "fr"], "source": { "version": 1, "state": "FROZEN", "durationMs": "90000", "sourceAssetId": "ia_...", "media": { "inputFormat": "mov,mp4,m4a,3gp,3g2,mj2", "containerName": "mov,mp4,m4a,3gp,3g2,mj2", "audioStreamCount": 1, "video": true }, "availableExportFormats": ["mp3", "wav", "flac", "mp4"] }, "targets": [ { "targetId": "it_...", "language": "es", "state": "READY", "characters": "6000", "billingState": "SETTLED", "action": "NONE", "reservationCycle": 1, "outputAssetId": "ia_..." } ], "jobs": [ { "jobId": "ij_...", "projectId": "ip_...", "targetId": "it_...", "stage": "FETCH_AUDIO", "state": "READY", "nextPollAfterMs": null, "errorCode": null, "billingState": "SETTLED" } ], "createdAt": "2027-01-15T15:50:02", "updatedAt": "2027-01-15T15:57:12", "requestId": "..." } } ``` `action` is `RETRY` only for a target in `FAILED_RELEASED`; all other states report `NONE`. `RECONCILING` on a target or job means the outcome is still being reconciled — it is not a failure and not a refund. ### Common errors * `code = 47102`: the project does not exist **or** is not owned by your account. The API never distinguishes the two. # Get upload status Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/getUpload GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/{uploadId} Check how many parts have been received and whether the source is ready. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Use this to resume an interrupted multipart upload and to wait for the probe to finish. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The upload session identifier. ### Response The upload session. Project identifier. `CREATED`, `UPLOADING`, `COMPLETING`, `PROBING`, `READY`, `FAILED`, `SUPERSEDED`, `EXPIRED` or `ABORTED`. The declared byte count, as a **string**. The assembled byte count, as a **string** or `null`. Bytes received so far, as a **string**. Part size for this session. Number of parts expected. `{ partNumber, etag, size }` for each part the service has already accepted. `size` is a **string**. Set when the upload failed. The created asset, once available. The committed source version. Detected duration, as a **string**. `{ inputFormat, containerName, audioStreamCount, video, width, height, rotationDegrees }`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/iu_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "uploadId": "iu_...", "projectId": "ip_...", "state": "READY", "declaredSize": "18432611", "actualSize": "18432611", "uploadedBytes": "18432611", "partSizeBytes": 16777216, "totalParts": 2, "uploadedParts": [ { "partNumber": 1, "etag": "", "size": "16777216" } ], "errorCode": null, "sourceAssetId": "ia_...", "sourceVersion": 1, "durationMs": "90000", "media": { "inputFormat": "mov,mp4,m4a,3gp,3g2,mj2", "containerName": "mov,mp4,m4a,3gp,3g2,mj2", "audioStreamCount": 1, "video": true }, "requestId": "..." } } ``` `COMPLETING` and `PROBING` do **not** mean the source can be used for generation yet. Only `READY` does. Poll while the state is `CREATED`, `UPLOADING`, `COMPLETING` or `PROBING`. ### Common errors * `code = 47124`: the upload session does not exist or is not owned by your account. * `code = 47125`: the assembled file exceeded the limit or had no content. * `code = 47127`: object storage was unavailable. # List interpretation projects Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/listProjects GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects Page through the Interpretation projects owned by your account. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Query Page number, `>= 1`. Page size: `10`, `20` or `50`. ### Response Echoed page number. Echoed page size. Total number of projects. Total number of pages. Entries shaped `{ projectId, name, state, summaryState, sourceDurationMs, targetLanguageCount, readyTargetCount, updatedAt }`. `sourceDurationMs` is a **string**. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects?page=1&pageSize=20' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "page": 1, "pageSize": 20, "total": 1, "totalPage": 1, "list": [ { "projectId": "ip_...", "name": "Launch video ES/FR", "state": "PROCESSING", "summaryState": "PARTIAL_READY", "sourceDurationMs": "90000", "targetLanguageCount": 2, "readyTargetCount": 1, "updatedAt": "2027-01-15T15:56:40" } ], "requestId": "..." } } ``` `summaryState` is a rolled-up statistic and deliberately does not overstate progress: `PARTIAL_READY` means some target languages are ready and some are not. ### Common errors * `code = 47101`: `page` is below `1`, or `pageSize` is not `10`, `20` or `50`. # Patch the interpretation draft Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/patchDraft PATCH https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/draft Update the source language, keyterms, cloning strength and target languages of a draft. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Updates only the fields you provide. This is a patch, not a replace. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body Optional concurrency guard. If present and different from the current version, the request is rejected with `47116`. `null`, an empty string or `AUTO` normalizes to automatic detection. **Omitting the field keeps the stored value** — it does not clear it. Replaces the whole list when provided. Up to 1000 entries; each up to 50 code points, up to 5 words, and without `< > { } [ ] \`. An empty array clears the list. `0`–`10`. When omitted or `null`, the stored value is kept; `7` is only used as a fallback when the draft has no value at all. Replaces the whole list when provided. An empty array clears the selection. ### Response Project identifier. The new draft version. The project state. The stored source language, or `null` for auto-detection. The stored keyterms. The stored cloning strength. The stored target languages. Source duration as a **string** (`"0"` before a source is uploaded). The source state: `DRAFT`, `FROZEN` or `SUPERSEDED`. ```bash theme={null} curl --location --request PATCH 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../draft' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "expectedVersion": 1, "sourceLanguage": "en", "targetLanguages": ["es", "fr"], "keyterms": ["MyVocal"], "cloningStrength": 7 }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "ip_...", "settingsVersion": 2, "state": "DRAFT", "sourceLanguage": "en", "keyterms": ["MyVocal"], "cloningStrength": 7, "targetLanguages": ["es", "fr"], "sourceDurationMs": "0", "sourceState": "DRAFT", "requestId": "..." } } ``` "Field omitted or `null`" keeps the current value for `sourceLanguage`, `keyterms`, `cloningStrength` and `targetLanguages`; a provided array — including an empty one — **replaces** the whole list. Do not use `null` to clear a field. ### Common errors * `code = 47116`: `expectedVersion` does not match the current version. * `code = 47123`: the draft is frozen because a source version was already committed; remove the source first. * `code = 47101`: an invalid value, for example a keyterm that is too long or contains a forbidden character. * `code = 47102`: the project does not exist **or** is not owned by your account. # Play an interpretation asset Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/playback GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/assets/{assetId}/playback Get a temporary URL for a finished language version. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Returns a temporary product URL for an asset, such as a finished target language. Take the `assetId` from `targets[].outputAssetId` in the project detail. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The asset identifier. ### Response The asset identifier. The asset state. The media type of the asset. The temporary playback URL. When the URL stops working. The stored asset version, or `null` when no storage version is recorded. Whether the URL supports range requests. How many renewal attempts one failed request may use before the authorization error is surfaced. Currently `1`: renew once, then report the error instead of retrying without bound. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/assets/ia_.../playback' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "assetId": "ia_...", "state": "READY", "mimeType": "audio/mpeg", "url": "https:///...", "expiresAt": "2027-01-15T16:10:00", "assetVersion": "1", "rangeSupported": true, "renewalAttemptLimit": 1, "requestId": "..." } } ``` The URL is temporary. Request it when you need to play the audio and request a new one after it expires rather than storing it. ### Common errors * `code = 47102`: the asset does not exist **or** is not owned by your account. The API does not distinguish the two. * `code = 47127`: object storage is unavailable — retry. # Rename an interpretation project Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/renameProject PATCH https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/name Change the display name of an Interpretation project. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body The new name: non-empty after trimming, at most 120 code points. ### Response A success envelope with no data payload. ```bash theme={null} curl --location --request PATCH 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../name' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "name": "Launch video (ES/FR) v2" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": null, "requestId": "..." } ``` ### Common errors * `code = 47101`: the name is missing, empty or too long. * `code = 47102`: the project does not exist **or** is not owned by your account. # Get a retry plan Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/retryPlan GET https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/targets/{targetId}/retry-plan Ask the server what a retry of a failed target would cost and which cycle it would use. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Only a target in `FAILED_RELEASED` with `action = "RETRY"` can be retried. This endpoint returns the server's plan; the client never prices a retry. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. The target language entry to retry. ### Response The target identifier. The target language. The logical generation the retry would continue. The reservation cycle the retry would use. Pass it to the retry endpoint. The Characters the retry would confirm, as a **string**. The rate version applied. Whether a retry is currently allowed. A human-readable reason. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../targets/it_.../retry-plan' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "targetId": "it_...", "language": "es", "generationId": "ia_...", "nextReservationCycle": 2, "characters": "6000", "rateVersion": "interp-2026-09-27-v1", "retryable": true, "reason": "PREVIOUS_ATTEMPT_RELEASED", "requestId": "..." } } ``` ### Common errors * `code = 47117`: the target does not exist, is not part of this project, or is not owned by your account. * `code = 47118`: the target is not in a retryable state. * `code = 47102`: the project does not exist **or** is not owned by your account. # Retry a failed target Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/retryTarget POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/{projectId}/targets/{targetId}/retry Confirm the server's retry plan and restart the failed target language. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Restarts one target language that ended in `FAILED_RELEASED`. The amount fields you send are a **confirmation of the server's plan**, taken from the retry plan — not client-side pricing. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per operation: 16–64 printable ASCII characters. `OPERATION_RETRY` is replay-safe, so a repeated POST with the same key does not create a second charge. ### Path The project identifier. The target to retry. ### Body From the retry plan. From the retry plan. Confirms the server's amount; do not compute it yourself. From the retry plan. ### Response The target identifier. The target language. The logical generation being retried. The new target state. The reservation cycle used. Reserved Characters, as a **string**. A human-readable message. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../targets/it_.../retry' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 2b8f0d47c1e35a90' \ --data '{ "nextReservationCycle": 2, "characters": 6000, "rateVersion": "interp-2026-09-27-v1" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "targetId": "it_...", "language": "es", "generationId": "ia_...", "state": "QUEUED", "reservationCycle": 2, "reservedCharacters": "6000", "message": "Retry accepted.", "requestId": "..." } } ``` Do not adjust or recompute `characters`. If the plan is no longer valid, request a new retry plan instead of guessing a new amount. ### Common errors * `code = 47118`: the target cannot be retried (wrong state or a stale plan). * `code = 47110`: not enough Characters available. * `code = 47117`: the target does not exist, is not part of this project, or is not owned by your account. * `code = 47111`: the `Idempotency-Key` was reused with a different body. # Sign an upload part Source: https://wiz-myvocal.mintlify.app/api-reference/interpretation/signUploadPart POST https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/{uploadId}/parts Get a presigned URL for one part of an upload session. **Interpretation** · Translate and dub uploaded audio/video · Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Requests a presigned URL for one part number. You then `PUT` that part's bytes directly to the returned URL. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The upload session identifier. ### Body The part to sign: from `1` to `totalParts`. ### Response The upload session. The signed part. The HTTP method to use, normally `PUT`. The presigned URL to send the part bytes to. Headers that must be included with the request to the presigned URL. When the presigned URL expires (15 minutes by default). Request it again for the same part if it expires. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/iu_.../parts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "partNumber": 1 }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "uploadId": "iu_...", "partNumber": 1, "method": "PUT", "url": "https:///...", "requiredHeaders": { "Content-Length": "16777216" }, "expiresAt": "2027-01-15T16:07:11", "requestId": "..." } } ``` The presigned URL points at object storage, **not** at MyVocal. Do not send your `accessKey` or any credential to it: the URL's signature is the authorization, and it is already scoped to this one part. ### Common errors * `code = 47126`: the part number is outside `1..totalParts`. * `code = 47124`: the upload session does not exist, is not owned by your account, or is no longer usable. * `code = 47127`: object storage is unavailable — retry. # Music capabilities Source: https://wiz-myvocal.mintlify.app/api-reference/music/capabilities GET https://api.myvocal.ai/sound_clone/api/v1/music/capabilities Read the Text-to-Music account state, rate card and accepted enum values. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Read this endpoint first. It tells you what the account may do and which enum values the write endpoints accept, so you never have to hard-code them. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Whether this account may use Text-to-Music: `ENABLED` or `DISABLED`. `DISABLED` means generation is not available for the account. The account's plan, for example `STANDARD`, `PRO`, `BUSINESS` or `ENTERPRISE`. Characters per minute for this account. The charge is `ceil(durationSec × ratePerMinute / 60)`. Version label of the applicable rate. `{ monthly, additional, total }`, each a **JSON string**. Convert before comparing. How long a quote stays valid. Currently `600`. The durations you may request: `60`, `90`, `120`, `180`. Entries shaped `{ code, name }`. Send the **`code`** as `vocalLanguage`, not the display name. Accepted `genre` values: `POP`, `ROCK`, `HIP_HOP`, `ELECTRONIC`, `RNB_SOUL`, `INDIE`, `JAZZ`, `CINEMATIC`, `FOLK_ACOUSTIC`, `LATIN`, `COUNTRY`, `CLASSICAL`. Accepted `moods` values: `UPLIFTING`, `ENERGETIC`, `ROMANTIC`, `DREAMY`, `MELANCHOLIC`, `DARK`, `CALM`, `HOPEFUL`, `DRAMATIC`, `PLAYFUL`, `NOSTALGIC`, `INTENSE`. Accepted `vocalStyle` values: `WARM_INTIMATE`, `BRIGHT_ENERGETIC`, `POWERFUL_ANTHEMIC`, `SOFT_BREATHY`. `AUTO`, `CUSTOM`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/capabilities' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "accessState": "ENABLED", "planKey": "PRO", "ratePerMinute": 1920, "rateVersion": "music-2026-08-26-v1", "balances": { "monthly": "10500", "additional": "0", "total": "10500" }, "quoteTtlSeconds": 600, "supportedDurationsSec": [60, 90, 120, 180], "supportedVocalLanguages": [ { "code": "en", "name": "English" } ], "genres": ["POP", "ROCK", "HIP_HOP", "ELECTRONIC", "RNB_SOUL", "INDIE", "JAZZ", "CINEMATIC", "FOLK_ACOUSTIC", "LATIN", "COUNTRY", "CLASSICAL"], "moods": ["UPLIFTING", "ENERGETIC", "ROMANTIC", "DREAMY", "MELANCHOLIC", "DARK", "CALM", "HOPEFUL", "DRAMATIC", "PLAYFUL", "NOSTALGIC", "INTENSE"], "vocalStyles": ["WARM_INTIMATE", "BRIGHT_ENERGETIC", "POWERFUL_ANTHEMIC", "SOFT_BREATHY"], "lyricsModes": ["AUTO", "CUSTOM"], "requestId": "..." } } ``` ### Common errors * `code = 401`, `"Key verification failed"`: the `accessKey` is missing, invalid or disabled. This is returned with HTTP `200` and **no** `data` field. * `code = 47018`: Text-to-Music is not available for this account or cohort. # Generate the song Source: https://wiz-myvocal.mintlify.app/api-reference/music/createGeneration POST https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/generations Accept a quote and start the song generation job. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Accepts a quote, reserves its Characters and queues a `SONG` job. The call returns immediately; it does not wait for the song. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per operation: 16–64 printable ASCII characters. Same key with the same body replays; same key with a different body is rejected with `47008`. ### Path The project identifier. ### Body The quote to accept. A quote can be consumed only once. ### Response Project identifier. The song job to poll. `SONG`. `QUEUED`. Characters reserved for this generation, as a **string**. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../generations' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 3ce1a94f6d0b28e5' \ --data '{ "quoteId": "muq_..." }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "jobId": "muj_...", "jobType": "SONG", "status": "QUEUED", "reservedCharacters": "3330", "createdAt": "2027-01-15T15:52:11", "requestId": "..." } } ``` ```json 200 Replay with the same key and body theme={null} { "code": 1, "message": "success", "data": { "jobId": "muj_...", "projectId": "mup_...", "jobType": "SONG", "status": "GENERATING", "displayStage": "CREATING_MUSIC_AND_VOCALS", "terminal": false, "failure": null, "attemptCount": null, "createdAt": "2027-01-15T15:52:11", "updatedAt": "2027-01-15T15:55:01", "requestId": "..." } } ``` A replay re-reads the job: the field set and the status can differ from the first response. Use `jobId` to query the job rather than parsing the replay as if it were the original create payload. ### Common errors * `code = 47007`: this quote has already been consumed. Query the existing project/job instead of submitting again. * `code = 47006`: the quote has expired. Request a new quote. * `code = 47005`: not enough Characters available. * `code = 47008`: the `Idempotency-Key` was reused with a different body. * `code = 47010`: another generation is already in progress for this project. * `code = 47009`: the project does not exist **or** is not owned by your account. # Create a music project Source: https://wiz-myvocal.mintlify.app/api-reference/music/createProject POST https://api.myvocal.ai/sound_clone/api/v1/music/projects Start a Text-to-Music project from a creative brief. Returns the project and its arrangement job. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Creates the project and immediately queues the **arrangement** stage. This is asynchronous: the response does not contain a song. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per distinct operation: 16–64 printable ASCII characters. Same key with the same body replays safely; same key with a different body is rejected with `47008`. ### Body What the song is about. 1–800 code points. One of the values from `capabilities.genres`. Optional production notes, 0–120 code points. `null` is normalized to `""`. 1–3 distinct values from `capabilities.moods`. A `code` from `capabilities.supportedVocalLanguages` (for example `en`). One of `capabilities.supportedDurationsSec`: `60`, `90`, `120` or `180`. `AUTO` or `CUSTOM`. With `AUTO`, `customLyrics` must be absent or empty. Required content only with `lyricsMode: "CUSTOM"` (20–2800 code points). Normalized to `null` under `AUTO`. One of the values from `capabilities.vocalStyles`. ### Response Stable project identifier. Keep it — it is your recovery anchor. `ARRANGEMENT_GENERATING` right after creation. `{ jobId, jobType: "ARRANGEMENT", status: "QUEUED" }`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 6f1c1f0e0b8a4d1e' \ --data '{ "description": "An upbeat summer pop song about a road trip along the coast.", "genre": "POP", "styleNotes": "Bright synths, driving drums, warm bass.", "moods": ["UPLIFTING", "ENERGETIC"], "vocalLanguage": "en", "durationSec": 90, "lyricsMode": "AUTO", "vocalStyle": "BRIGHT_ENERGETIC" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "projectStatus": "ARRANGEMENT_GENERATING", "job": { "jobId": "muj_...", "jobType": "ARRANGEMENT", "status": "QUEUED" }, "requestId": "..." } } ``` ```json 200 Replay with the same key and body theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "name": "Coast Road", "projectStatus": "ARRANGEMENT_READY", "arrangementVersion": 1, "arrangement": { "...": "..." }, "activeJob": { "jobId": "muj_...", "status": "READY" }, "requestId": "..." } } ``` A replay is **not** the first response replayed byte-for-byte: it re-reads the current project and may return the full project detail instead. Use `projectId` to query the resource. ### Common errors * `code = 47001`: the brief failed validation (unknown enum, wrong duration, mood list empty or duplicated, description out of range). * `code = 47008`: the `Idempotency-Key` was reused with a different body. * `code = 47011`: temporarily unavailable — retry with backoff. * `code = 47018`: Text-to-Music is not available for this account or cohort. # Quote a music generation Source: https://wiz-myvocal.mintlify.app/api-reference/music/createQuote POST https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/quotes Price the next generation for the current arrangement. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Quoting is free. It tells you the exact Characters charge, whether the account can afford it, and how long the quote stays valid. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body The arrangement version to price. ### Response Identifier to pass to the generation endpoint. Project identifier. Priced arrangement version. The plan the rate came from. Characters per minute applied. Version label of the applied rate. Priced duration. The price, as a **JSON string**. `ceil(durationSec × ratePerMinute / 60)`. When the quote stops being valid. The time to live is `quoteTtlSeconds` (normally `600`). Whether the balance covers the quote. How much is missing; `"0"` when affordable. Projected balance after the charge. `{ monthly, additional, total }`, each a **string**. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../quotes' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "arrangementVersion": 1 }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "quoteId": "muq_...", "projectId": "mup_...", "arrangementVersion": 1, "planKey": "POPULAR", "ratePerMinute": 2220, "rateVersion": "music-2026-08-26-v1", "durationSec": 90, "quotedCharacters": "3330", "expiresAt": "2027-01-15T16:00:00", "affordable": true, "shortfall": "0", "remainingAfterGeneration": "7170", "balances": { "monthly": "10500", "additional": "0", "total": "10500" }, "requestId": "..." } } ``` Every Characters value is a **JSON string**, because 64-bit integers are serialized as strings to preserve precision. Convert to an integer before comparing or subtracting — never compare them as strings. ### Common errors * `code = 47001`: `arrangementVersion` is missing or invalid. * `code = 47009`: the project does not exist **or** is not owned by your account. * `code = 47003` / `47004`: entitlement is still syncing or undecided; retry shortly. # Create a project version Source: https://wiz-myvocal.mintlify.app/api-reference/music/createVersion POST https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/versions Branch a child project from the current arrangement. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Creates a child project that starts from the parent's current arrangement, so you can iterate without losing the original. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per operation: 16–64 printable ASCII characters. Same key with a different body is rejected with `47008`. ### Path The parent project identifier. ### Body Must be `CURRENT_ARRANGEMENT`. Any other value is rejected with `47001`. ### Response Returns the full detail of the **child** project (same shape as `GET /projects/{projectId}`), with `parentProjectId` set to the parent. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../versions' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 7d2e5b41c9a30f86' \ --data '{ "copy": "CURRENT_ARRANGEMENT" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_child...", "parentProjectId": "mup_...", "projectStatus": "ARRANGEMENT_READY", "arrangementVersion": 1, "requestId": "..." } } ``` For this endpoint the first response and the replay have the **same shape** (project detail), but the field values change as the project progresses. Use the child `projectId` as the stable anchor. ### Common errors * `code = 47001`: `copy` is missing or is not `CURRENT_ARRANGEMENT`. * `code = 47008`: the `Idempotency-Key` was reused with a different body. * `code = 47009`: the parent project does not exist **or** is not owned by your account. # Delete a music project Source: https://wiz-myvocal.mintlify.app/api-reference/music/deleteProject DELETE https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId} Delete a music project owned by your account. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Response A success envelope with no data payload. ```bash theme={null} curl --location --request DELETE 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": null, "requestId": "..." } ``` The delete is scoped to your ownership and is idempotent: a project that does not exist, or that belongs to another account, returns the same success. Success therefore means "this call needs no further delete handling" — it is **not** proof that the project existed or that this call removed it. Nothing about another account's data is affected or disclosed. ### Common errors * `code = 47017`: a generation is still in flight for this project. The job is **not** cancelled; wait for it and retry the delete. # Download the song Source: https://wiz-myvocal.mintlify.app/api-reference/music/download GET https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/download Stream the finished song as MP3 bytes. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) This endpoint does **not** return the usual JSON envelope on success. Success is an `audio/mpeg` byte stream. A rejected request, by contrast, is answered with the standard JSON error envelope. Check `Content-Type` (or the JSON `code`) before writing the file, so an error message is never saved as an `.mp3`. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. The song must be `READY` with a usable `readyAsset`. ### Response `audio/mpeg` on success; a JSON content type when the request is rejected. `attachment; filename="MyVocal-.mp3"`. MP3 audio bytes. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../download' \ --header 'accessKey: ' \ --output song.mp3 ``` ```text 200 Success theme={null} Content-Type: audio/mpeg Content-Disposition: attachment; filename="MyVocal-Coast Road.mp3" (MP3 byte stream) ``` ```json 200 Fail theme={null} { "code": 47015, "message": "Download is temporarily unavailable.", "data": { "errorCode": "47015", "messageKey": "...", "retryable": true, "action": "RETRY_LATER", "requestId": "..." } } ``` ### Common errors * `code = 47009`: the project does not exist **or** is not owned by your account. * `code = 47015`: the song is not ready to download yet, or storage is temporarily unavailable — poll the project and retry. # Get a music job Source: https://wiz-myvocal.mintlify.app/api-reference/music/getJob GET https://api.myvocal.ai/sound_clone/api/v1/music/jobs/{jobId} Read the progress of an arrangement or song job. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The job identifier returned by create, regenerate or generate. ### Response Job identifier. The project this job belongs to. `ARRANGEMENT` or `SONG`. `QUEUED`, `GENERATING`, `FINALIZING`, `SETTLING`, `READY`, `FAILED` or `RECOVERY_REQUIRED`. Coarser user-facing stage: `QUEUED`, `CREATING_MUSIC_AND_VOCALS`, `FINALIZING_LIBRARY_ITEM` or `RECOVERY_REQUIRED`. `true` only for `READY`, `FAILED` and `RELEASED`. Populated when the job failed. How many delivery attempts this `ARRANGEMENT` job has had, as a decimal **string** (for example `"0"` or `"3"`). `null` for `SONG` jobs, which do not use the arrangement retry counter. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/jobs/muj_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "jobId": "muj_...", "projectId": "mup_...", "jobType": "SONG", "status": "GENERATING", "displayStage": "CREATING_MUSIC_AND_VOCALS", "terminal": false, "failure": null, "attemptCount": null, "createdAt": "2027-01-15T15:53:20", "updatedAt": "2027-01-15T15:55:01", "requestId": "..." } } ``` An `ARRANGEMENT` job reaching `READY` means the arrangement is complete, **not** that a song can be downloaded. Downloading requires `projectStatus = READY` with a usable `readyAsset`. ### Common errors * `code = 47009`: the job does not exist **or** does not belong to your account. * `code = 47011`: temporarily unavailable — retry with backoff. # Get a music project Source: https://wiz-myvocal.mintlify.app/api-reference/music/getProject GET https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId} Read the current state of a Text-to-Music project, including its arrangement, quote and ready asset. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) This is the main polling endpoint for Text-to-Music. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier returned by create. ### Response Project identifier. Set on a child version created by `POST /versions`. Project name. `ARRANGEMENT_GENERATING`, `ARRANGEMENT_READY`, `GENERATING`, `READY` or `DELETED`. `ARRANGEMENT_READY` means the arrangement is done — not that the song exists. The validated creative brief. Current arrangement version. Use it as `expectedVersion` when you edit or regenerate. The current arrangement, or `null` before it exists. `{ quoteId, arrangementVersion, planKey, ratePerMinute, rateVersion, durationSec, quotedCharacters, expiresAt }`. `quotedCharacters` is a **string**. `{ jobId, jobType, status, attemptCount, createdAt, updatedAt, displayStage, terminal }`. `attemptCount` is a decimal **string** for an `ARRANGEMENT` job (for example `"0"`) and `null` for a `SONG` job. Present when the song is downloadable: `{ assetId, durationMillis, sampleRateHz, mimeType }`. `durationMillis` is a **string**. `{ code, errorCode, retryable, action }` when the work failed. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. Timestamp, `yyyy-MM-dd'T'HH:mm:ss`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_...' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "parentProjectId": null, "name": "Coast Road", "projectStatus": "READY", "arrangementVersion": 1, "activeQuote": null, "activeJob": { "jobId": "muj_...", "jobType": "SONG", "status": "READY", "displayStage": "FINALIZING_LIBRARY_ITEM", "terminal": true }, "readyAsset": { "assetId": "ma_...", "durationMillis": "90000", "sampleRateHz": 44100, "mimeType": "audio/mpeg" }, "lastFailure": null, "createdAt": "2027-01-15T15:50:02", "updatedAt": "2027-01-15T15:56:40", "requestId": "..." } } ``` ### Common errors * `code = 47009`: the project does not exist **or** does not belong to your account. The API never distinguishes the two. # List music projects Source: https://wiz-myvocal.mintlify.app/api-reference/music/listProjects GET https://api.myvocal.ai/sound_clone/api/v1/music/projects Page through the Text-to-Music projects owned by your account. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Query Page number, `>= 1`. Page size: `10`, `20` or `50`. ### Response Echoed page number. Echoed page size. Total number of projects. Total number of pages. Entries shaped `{ projectId, name, projectStatus, createdAt, updatedAt }`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects?page=1&pageSize=20' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "page": 1, "pageSize": 20, "total": 3, "totalPage": 1, "list": [ { "projectId": "mup_...", "name": "Coast Road", "projectStatus": "READY", "createdAt": "2027-01-15T15:50:02", "updatedAt": "2027-01-15T15:56:40" } ], "requestId": "..." } } ``` ### Common errors * `code = 47001`: `page` is below `1`, or `pageSize` is not `10`, `20` or `50`. # Get a playback URL Source: https://wiz-myvocal.mintlify.app/api-reference/music/playbackUrl GET https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/playback-url Get a temporary URL that plays the finished song. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Use this to preview or stream the finished song without downloading the whole file. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Response The finished audio asset. Temporary URL for the audio. When the URL stops working. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../playback-url' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "assetId": "ma_...", "url": "https:///...", "expiresAt": "2027-01-15T16:10:00", "requestId": "..." } } ``` The URL is short-lived (about 10 minutes). Request it when you need to play the audio instead of storing it, and request a fresh one after it expires. ### Common errors * `code = 47009`: the project does not exist **or** is not owned by your account. * `code = 47015`: the download/playback source is temporarily unavailable because the song is not ready yet. # Regenerate the arrangement Source: https://wiz-myvocal.mintlify.app/api-reference/music/regenerateArrangement POST https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/arrangement/regenerate Ask the service for a new arrangement for the current brief. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Queues a new `ARRANGEMENT` job for the project's current brief. Use this when you would rather get a fresh arrangement than edit the existing one. ### Header Your API key. See [Authentication](/api-reference/authentication). Unique per operation: 16–64 printable ASCII characters. Same key with a different body is rejected with `47008`. ### Path The project identifier. ### Body The `arrangementVersion` you based this request on. A mismatch is rejected with `47016`. ### Response Project identifier. The new arrangement job. `ARRANGEMENT`. `QUEUED`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../arrangement/regenerate' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 91b7c0de4a2f57c3' \ --data '{ "expectedVersion": 1 }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "jobId": "muj_...", "jobType": "ARRANGEMENT", "status": "QUEUED", "requestId": "..." } } ``` ```json 200 Replay with the same key and body theme={null} { "code": 1, "message": "success", "data": { "jobId": "muj_...", "projectId": "mup_...", "jobType": "ARRANGEMENT", "status": "READY", "displayStage": "QUEUED", "terminal": true, "failure": null, "attemptCount": "0", "requestId": "..." } } ``` A replay re-reads the job instead of replaying the first response byte-for-byte: the same key can return the job read model, with a different field set and a later status. Use `jobId` to query the job. ### Common errors * `code = 47016`: `expectedVersion` does not match. Re-read the project and retry. * `code = 47008`: the `Idempotency-Key` was reused with a different body. * `code = 47009`: the project does not exist **or** is not owned by your account. * `code = 47010`: another operation is already in progress for this project. # Rename a music project Source: https://wiz-myvocal.mintlify.app/api-reference/music/renameProject PATCH https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/name Change the display name of a music project. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body The new name: non-empty after trimming, at most 120 code points. ### Response A success envelope with no data payload. ```bash theme={null} curl --location --request PATCH 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../name' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "name": "Coast Road (final)" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": null, "requestId": "..." } ``` ### Common errors * `code = 47001`: the name is missing, empty or too long. * `code = 47009`: the project does not exist **or** is not owned by your account. # Edit the arrangement Source: https://wiz-myvocal.mintlify.app/api-reference/music/updateArrangement PUT https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/arrangement Edit an arrangement by merging the editable fields into the current immutable arrangement. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) The body is an **edit request**, not a whole arrangement. The service merges your edit into the current immutable arrangement and re-validates the result. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body The `arrangementVersion` you based this edit on. A mismatch is rejected with `47016`. Song title, 1–120 code points. Summary of the musical style, 1–500 code points. `null`, or between `40` and `220`. Sections to merge, addressed by `sectionId`: `{ sectionId, lyrics, styleNotes }`, in section order. ### Validation rules The merged arrangement must satisfy: * 4–12 sections; every section `position` must equal its 1-based index. * Section types: `INTRO`, `VERSE`, `PRE_CHORUS`, `CHORUS`, `BRIDGE`, `OUTRO`, `OTHER`. * Each section `durationSec` is 5–60, and the durations must sum to the arrangement duration. * At least one `VERSE` and one `CHORUS` must be present. * Concatenated `lyrics`, trimmed, must be 20–2800 code points. ### Response Project identifier. The new arrangement version. The merged, validated arrangement. ```bash theme={null} curl --location --request PUT 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../arrangement' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "expectedVersion": 1, "title": "Coast Road", "styleSummary": "Bright summer pop with driving drums.", "tempoBpm": 118, "sections": [ { "sectionId": "", "lyrics": "Where the highway meets the sea...", "styleNotes": "Warm pads" } ] }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "version": 2, "arrangement": { "durationSec": 90, "sections": [ "..." ], "requestId": "..." } } } ``` Editing the arrangement makes the current quote stale. Request a new quote before generating. ### Common errors * `code = 47016`: `expectedVersion` does not match the current arrangement version. Re-read the project and retry. * `code = 47001`: the merge produced an arrangement that violates a validation rule. * `code = 47009`: the project does not exist **or** is not owned by your account. # Update the creative brief Source: https://wiz-myvocal.mintlify.app/api-reference/music/updateBrief PUT https://api.myvocal.ai/sound_clone/api/v1/music/projects/{projectId}/brief Replace the creative brief of a music project. Invalidates the current quote. **Text to Music** · Workflow: [Text-to-Music quickstart](/guides/music-quickstart) · Polling: [Async jobs and retries](/guides/async-jobs-and-retries) Replaces the whole brief and re-validates it with the same rules as create. An existing quote becomes stale, so quote again before generating. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path The project identifier. ### Body The body is the same `CreativeBrief` used by `POST /projects`: 1–800 code points. One of `capabilities.genres`. Optional, 0–120 code points. 1–3 distinct values from `capabilities.moods`. A `code` from `capabilities.supportedVocalLanguages`. `60`, `90`, `120` or `180`. `AUTO` or `CUSTOM`. Only used with `CUSTOM` (20–2800 code points). One of `capabilities.vocalStyles`. ### Response Returns the full project detail, identical in shape to `GET /projects/{projectId}`. ```bash theme={null} curl --location --request PUT 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../brief' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "description": "A calmer indie folk song about autumn evenings.", "genre": "FOLK_ACOUSTIC", "styleNotes": "Fingerpicked guitar, soft brushes.", "moods": ["CALM", "NOSTALGIC"], "vocalLanguage": "en", "durationSec": 120, "lyricsMode": "AUTO", "vocalStyle": "WARM_INTIMATE" }' ``` ```json 200 Success theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "projectStatus": "ARRANGEMENT_GENERATING", "arrangementVersion": 2, "activeQuote": null, "requestId": "..." } } ``` ### Common errors * `code = 47001`: the brief failed validation. * `code = 47009`: the project does not exist **or** is not owned by your account. * `code = 47010`: another operation is already in progress for this project. # API directory Source: https://wiz-myvocal.mintlify.app/api-reference/overview Every MyVocal API endpoint, grouped by product, with links to the full reference. All endpoints use the host `https://api.myvocal.ai` and the `accessKey` header ([Authentication](/api-reference/authentication)). Each product section links to its quickstart for the end-to-end workflow. ## Account | Endpoint | Method | Path | | - | - | - | | [Get account information](/api-reference/user/getInfo) | `GET` | `/sound_clone/api/v1/user/info` | ## Text to Speech Workflow: [TTS quickstart](/quickstart) ### TTS API reference | Endpoint | Method | Path | | - | - | - | | [Create speech](/api-reference/tts/tts) | `POST` | `/sound_clone/api/v1/tts` | | [Stream speech](/api-reference/tts/ttsStream) | `POST` | `/sound_clone/api/v1/tts/stream` | ### TTS History | Endpoint | Method | Path | | - | - | - | | [List TTS history](/api-reference/history/ttsList) | `GET` | `/sound_clone/api/v1/tts/list` | | [Get TTS audio URLs](/api-reference/history/ttsListUrl) | `POST` | `/sound_clone/api/v1/tts/query` | | [Delete TTS history](/api-reference/history/deleteTTS) | `DELETE` | `/sound_clone/api/v1/tts` | Models: [TTS Models & Migration](/api-reference/tts/models) · [V3 language codes](/api-reference/tts/v3-language-codes) ## Speech to Text Workflow: [Batch quickstart](/guides/stt-batch-quickstart) · [Real-time quickstart](/guides/stt-realtime-quickstart) ### STT API reference | Endpoint | Method | Path | | - | - | - | | [Speech to Text capabilities](/api-reference/stt/capabilities) | `GET` | `/sound_clone/api/v1/stt/capabilities` | #### Batch uploads | Endpoint | Method | Path | | - | - | - | | [Create an upload](/api-reference/stt/createUpload) | `POST` | `/sound_clone/api/v1/stt/uploads` | | [Sign an upload part](/api-reference/stt/signUploadPart) | `POST` | `/sound_clone/api/v1/stt/uploads/{uploadId}/parts/{partNumber}` | | [Complete an upload](/api-reference/stt/completeUpload) | `POST` | `/sound_clone/api/v1/stt/uploads/{uploadId}/complete` | | [Get an upload](/api-reference/stt/getUpload) | `GET` | `/sound_clone/api/v1/stt/uploads/{uploadId}` | #### Batch transcriptions | Endpoint | Method | Path | | - | - | - | | [Create a transcription](/api-reference/stt/createTranscription) | `POST` | `/sound_clone/api/v1/stt/transcriptions` | | [Get a transcription](/api-reference/stt/getTranscription) | `GET` | `/sound_clone/api/v1/stt/transcriptions/{transcriptionId}` | | [List transcriptions](/api-reference/stt/listTranscriptions) | `GET` | `/sound_clone/api/v1/stt/transcriptions` | | [Download a transcription](/api-reference/stt/downloadTranscription) | `GET` | `/sound_clone/api/v1/stt/transcriptions/{transcriptionId}/download` | | [Delete a transcription](/api-reference/stt/deleteTranscription) | `DELETE` | `/sound_clone/api/v1/stt/transcriptions/{transcriptionId}` | #### Real-time sessions | Endpoint | Method | Path | | - | - | - | | [Create a real-time session](/api-reference/stt/createSession) | `POST` | `/sound_clone/api/v1/stt/realtime/sessions` | | [Get a real-time session](/api-reference/stt/getSession) | `GET` | `/sound_clone/api/v1/stt/realtime/sessions/{sessionId}` | | [Pause a real-time session](/api-reference/stt/pauseSession) | `POST` | `/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/pause` | | [Resume a real-time session](/api-reference/stt/resumeSession) | `POST` | `/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/resume` | | [Finish a real-time session](/api-reference/stt/finishSession) | `POST` | `/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/finish` | | [Create a browser ticket](/api-reference/stt/createTicket) | `POST` | `/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/tickets` | SDKs: [Real-time SDKs](/sdks/stt-realtime/overview) (Java, Go, Python) · [Availability](/guides/stt-availability) ## Voice cloning Workflow: [How to use voices](/guides/voice-quickstart) ### Voice API reference | Endpoint | Method | Path | | - | - | - | | [Create a TTS voice](/api-reference/voice/addTTSVoice) | `POST` | `/sound_clone/api/v1/voices/tts` | | [Create a Cover voice](/api-reference/voice/addCoverVoice) | `POST` | `/sound_clone/api/v1/voices/vc` | | [Improve a TTS voice](/api-reference/voice/editTTSVoice) | `PUT` | `/sound_clone/api/v1/voices/tts/{voiceId}` | | [Improve a Cover voice](/api-reference/voice/editCoverVoice) | `PUT` | `/sound_clone/api/v1/voices/vc/{voiceId}` | | [List voices](/api-reference/voice/list) | `GET` | `/sound_clone/api/v1/voices` | | [Rename a voice](/api-reference/voice/updateVoiceName) | `PUT` | `/sound_clone/api/v1/voices/rename/{id}` | | [Delete a voice](/api-reference/voice/delete) | `DELETE` | `/sound_clone/api/v1/voices/{id}` | Cover voice training results are delivered by [Cover callbacks](/callback). ## AI Cover Workflow: [AI Cover quickstart](/guides/cover-quickstart) | Endpoint | Method | Path | | - | - | - | | [Generate a cover](/api-reference/cover/cover) | `POST` | `/sound_clone/api/v1/cover` | ### Cover History | Endpoint | Method | Path | | - | - | - | | [List Cover history](/api-reference/history/coverList) | `GET` | `/sound_clone/api/v1/cover/list` | | [Get Cover audio URLs](/api-reference/history/coverListUrl) | `POST` | `/sound_clone/api/v1/cover/query` | | [Delete Cover history](/api-reference/history/deleteCover) | `DELETE` | `/sound_clone/api/v1/cover` | Results of Generate a cover and of Cover voice training are delivered by [Cover callbacks](/callback). ## Text to Music Workflow: [Text-to-Music quickstart](/guides/music-quickstart) ### Music API reference | Endpoint | Method | Path | | - | - | - | | [Music capabilities](/api-reference/music/capabilities) | `GET` | `/sound_clone/api/v1/music/capabilities` | #### Create and generate | Endpoint | Method | Path | | - | - | - | | [Create a music project](/api-reference/music/createProject) | `POST` | `/sound_clone/api/v1/music/projects` | | [Get a music job](/api-reference/music/getJob) | `GET` | `/sound_clone/api/v1/music/jobs/{jobId}` | | [Get a music project](/api-reference/music/getProject) | `GET` | `/sound_clone/api/v1/music/projects/{projectId}` | | [Update the creative brief](/api-reference/music/updateBrief) | `PUT` | `/sound_clone/api/v1/music/projects/{projectId}/brief` | | [Edit the arrangement](/api-reference/music/updateArrangement) | `PUT` | `/sound_clone/api/v1/music/projects/{projectId}/arrangement` | | [Regenerate the arrangement](/api-reference/music/regenerateArrangement) | `POST` | `/sound_clone/api/v1/music/projects/{projectId}/arrangement/regenerate` | | [Quote a music generation](/api-reference/music/createQuote) | `POST` | `/sound_clone/api/v1/music/projects/{projectId}/quotes` | | [Generate the song](/api-reference/music/createGeneration) | `POST` | `/sound_clone/api/v1/music/projects/{projectId}/generations` | | [Get a playback URL](/api-reference/music/playbackUrl) | `GET` | `/sound_clone/api/v1/music/projects/{projectId}/playback-url` | | [Download the song](/api-reference/music/download) | `GET` | `/sound_clone/api/v1/music/projects/{projectId}/download` | #### Manage projects | Endpoint | Method | Path | | - | - | - | | [List music projects](/api-reference/music/listProjects) | `GET` | `/sound_clone/api/v1/music/projects` | | [Create a project version](/api-reference/music/createVersion) | `POST` | `/sound_clone/api/v1/music/projects/{projectId}/versions` | | [Rename a music project](/api-reference/music/renameProject) | `PATCH` | `/sound_clone/api/v1/music/projects/{projectId}/name` | | [Delete a music project](/api-reference/music/deleteProject) | `DELETE` | `/sound_clone/api/v1/music/projects/{projectId}` | ## Interpretation Translate and dub uploaded audio/video. It is not a real-time interpretation service. Workflow: [Interpretation quickstart](/guides/interpretation-quickstart) ### Interpretation API reference | Endpoint | Method | Path | | - | - | - | | [Interpretation capabilities](/api-reference/interpretation/capabilities) | `GET` | `/sound_clone/api/v1/interpretation/capabilities` | #### Upload the source | Endpoint | Method | Path | | - | - | - | | [Create an upload session](/api-reference/interpretation/createUpload) | `POST` | `/sound_clone/api/v1/interpretation/projects/{projectId}/uploads` | | [Sign an upload part](/api-reference/interpretation/signUploadPart) | `POST` | `/sound_clone/api/v1/interpretation/uploads/{uploadId}/parts` | | [Complete an upload](/api-reference/interpretation/completeUpload) | `POST` | `/sound_clone/api/v1/interpretation/uploads/{uploadId}/complete` | | [Get upload status](/api-reference/interpretation/getUpload) | `GET` | `/sound_clone/api/v1/interpretation/uploads/{uploadId}` | | [Remove the interpretation source](/api-reference/interpretation/deleteSource) | `DELETE` | `/sound_clone/api/v1/interpretation/projects/{projectId}/source` | #### Quote and generate | Endpoint | Method | Path | | - | - | - | | [Patch the interpretation draft](/api-reference/interpretation/patchDraft) | `PATCH` | `/sound_clone/api/v1/interpretation/projects/{projectId}/draft` | | [Quote interpretation targets](/api-reference/interpretation/createQuote) | `POST` | `/sound_clone/api/v1/interpretation/projects/{projectId}/quotes` | | [Accept an interpretation quote](/api-reference/interpretation/createGeneration) | `POST` | `/sound_clone/api/v1/interpretation/projects/{projectId}/generations` | | [Get an interpretation job](/api-reference/interpretation/getJob) | `GET` | `/sound_clone/api/v1/interpretation/jobs/{jobId}` | | [Get a retry plan](/api-reference/interpretation/retryPlan) | `GET` | `/sound_clone/api/v1/interpretation/projects/{projectId}/targets/{targetId}/retry-plan` | | [Retry a failed target](/api-reference/interpretation/retryTarget) | `POST` | `/sound_clone/api/v1/interpretation/projects/{projectId}/targets/{targetId}/retry` | #### Results and export | Endpoint | Method | Path | | - | - | - | | [Play an interpretation asset](/api-reference/interpretation/playback) | `GET` | `/sound_clone/api/v1/interpretation/assets/{assetId}/playback` | | [Create an export](/api-reference/interpretation/createExport) | `POST` | `/sound_clone/api/v1/interpretation/targets/{targetId}/exports` | | [Download an export](/api-reference/interpretation/downloadExport) | `GET` | `/sound_clone/api/v1/interpretation/exports/{exportId}/download` | #### Manage projects | Endpoint | Method | Path | | - | - | - | | [Create an interpretation project](/api-reference/interpretation/createProject) | `POST` | `/sound_clone/api/v1/interpretation/projects` | | [Get an interpretation project](/api-reference/interpretation/getProject) | `GET` | `/sound_clone/api/v1/interpretation/projects/{projectId}` | | [List interpretation projects](/api-reference/interpretation/listProjects) | `GET` | `/sound_clone/api/v1/interpretation/projects` | | [Rename an interpretation project](/api-reference/interpretation/renameProject) | `PATCH` | `/sound_clone/api/v1/interpretation/projects/{projectId}/name` | | [Delete an interpretation project](/api-reference/interpretation/deleteProject) | `DELETE` | `/sound_clone/api/v1/interpretation/projects/{projectId}` | ## Integration concepts * [Characters, quotes and billing](/guides/characters-and-quotes) * [Async jobs, polling and retries](/guides/async-jobs-and-retries) (Text to Music and Interpretation) # Speech to Text capabilities Source: https://wiz-myvocal.mintlify.app/api-reference/stt/capabilities GET https://api.myvocal.ai/sound_clone/api/v1/stt/capabilities Read the account state, rate, models and accepted option values for Batch and real-time. **Speech to Text** · Workflows: [Batch quickstart](/guides/stt-batch-quickstart) · [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) Read this endpoint first. It reports what the account may do and which option values the write endpoints accept, in MyVocal field names. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The default (Batch) model: `myvocal_stt_v1`. Real-time results report `myvocal_stt_realtime_v1`. `{ "batch": "AVAILABLE", "realtime": "AVAILABLE" }`. Each entry is `{ modelId, mode, state }`. A `state` of `AVAILABLE` means the model is ready to use. The accepted Batch submit surface and its constraints: the `uploadId` / `mediaUrl` choice (exactly one), `audioTrackIndex`, `languageHint`, `waitForCompletion` / `waitTimeoutMs`, every `options` field including `exportFormats` (pre-generation only), each `exportOptions[]` control, `notifyUrl` / `notifyOnCompletion` and `clientMetadata`. `options.processingContentStorage` notes that account eligibility is not verified; `options.matchKnownSpeakers` is listed as not available. The accepted real-time session options, for example `options.inputEncoding` and `options.segmentCommitMode`, plus the `Idempotency-Key` header requirement. Every format the download endpoint accepts: `txt`, `json`, `srt`, `segmented_json`, `html`, `docx`, `pdf`. The plan, rate and balances for this key's account. ```json theme={null} { "code": 1, "message": "success", "data": { "modelId": "myvocal_stt_v1", "modes": { "batch": "AVAILABLE", "realtime": "AVAILABLE" }, "models": [ { "modelId": "myvocal_stt_v1", "mode": "BATCH", "state": "AVAILABLE" }, { "modelId": "myvocal_stt_realtime_v1", "mode": "REALTIME", "state": "AVAILABLE" } ], "downloadFormats": ["txt", "json", "srt", "segmented_json", "html", "docx", "pdf"] } } ``` # Complete an upload Source: https://wiz-myvocal.mintlify.app/api-reference/stt/completeUpload POST https://api.myvocal.ai/sound_clone/api/v1/stt/uploads/{uploadId}/complete Complete the uploaded parts and analyze the audio. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) MyVocal API key. The upload id. All uploaded parts with their object-storage ETags. One-based part number. ETag returned by the storage PUT. ```json theme={null} {"parts":[{"partNumber":1,"etag":""}]} ``` Read `data.state` before submitting a transcription. A `READY` upload includes `media` and `media.audioTracks`; use the selected track's `index` as `audioTrackIndex` when multiple tracks exist. A `FAILED` upload reports `errorCode`; invalid audio can return `MEDIA_UNREADABLE`. HTTP 200 alone does not prove the file is ready. You can also [read the upload](/api-reference/stt/getUpload) to retrieve its current state. # Create a real-time session Source: https://wiz-myvocal.mintlify.app/api-reference/stt/createSession POST https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions Start a streaming transcription session and get its socket URL. **Speech to Text · Real-time** · Workflow: [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) Creates a real-time session. Audio is then streamed over the returned `streamUrl`. The session shares History and the Characters balance with Batch. ```bash cURL theme={null} # Generate the key once; reuse it and the same body if the response is lost. IDEMPOTENCY_KEY=$(python -c 'import uuid; print(uuid.uuid4())') curl --request POST \ --url https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions \ --header "accessKey: $MYVOCAL_ACCESS_KEY" \ --header "Idempotency-Key: $IDEMPOTENCY_KEY" \ --header 'Content-Type: application/json' \ --data '{"languageHint":"en","options":{"inputEncoding":"pcm_s16le_16000","segmentCommitMode":"manual"}}' ``` ```json 200 theme={null} { "code": 1, "message": "success", "data": { "sessionId": "", "transcriptionId": "", "status": "RECORDING", "modelId": "myvocal_stt_realtime_v1", "streamUrl": "", "effectiveOptions": {"inputEncoding":"pcm_s16le_16000","sampleRateHz":16000} } } ``` ### Header Your API key. See [Authentication](/api-reference/authentication). Binds this request. The same key and the same body (including `title` and `options`) return the same session; a changed title or option under the same key is `IDEMPOTENCY_CONFLICT`. ### Body The spoken language, or omit for automatic detection. A title for the History row, up to 200 characters. Defaults to a generic recording title. Optional processing controls. The byte format you will send: `pcm_s16le_8000`, `pcm_s16le_16000`, `pcm_s16le_22050`, `pcm_s16le_24000`, `pcm_s16le_44100`, `pcm_s16le_48000` or `mulaw_8000`. PCM is signed 16-bit little-endian mono; μ-law is one byte per sample. The chosen rate drives the whole session timeline. `manual` (you commit segments) or `vad` (the model decides segment boundaries). Candidate language hints, up to 8. This is not the detected language. Speech threshold for `vad`, between `0` and `1`. Silence before a `vad` commit, from 0 to 60000 milliseconds. Minimum speech length, an integer from 0 to 60000 milliseconds. Minimum silence length, an integer from 0 to 60000 milliseconds. Word and character alignment. Mutually exclusive with `options.suppressBackgroundSpeech`; when background filtering is on and this is unset, alignment defaults to off. Return the detected language. Key terms to bias recognition, up to 50 entries. Remove filler words. Detect entities of these categories. Mutually exclusive with `options.rewriteInstruction`. Instruction for an edited transcript, up to 2000 characters. Mutually exclusive with `options.entityCategories`. Filter background speech. Mutually exclusive with timestamps. Processing connection keepalive interval between `500` and `10000` milliseconds. This is not a client-to-MyVocal socket heartbeat; see [connection guidance](/guides/stt-realtime-quickstart#6-rotation-recovery-and-errors). Request processing-side content storage. Account eligibility is not verified; if the model returns a warning that it was not applied, the session reports a `PROCESSING_STORAGE_NOT_APPLIED` notice. Neither acceptance nor absence of a notice guarantees zero retention; see [current limitations](/guides/stt-availability). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The session id (`rts_...`). The History id (`stt_...`), the same entity Batch results use. The session state: `RECORDING`, `PAUSED` or `CLOSED`, or the task status once closed. `myvocal_stt_realtime_v1`. The MyVocal socket path. Connect it as a WebSocket; identity comes from the `accessKey` header or a ticket, never from the URL string alone. The options in effect, including the resolved `inputEncoding` and `sampleRateHz`. # Create a browser ticket Source: https://wiz-myvocal.mintlify.app/api-reference/stt/createTicket POST https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/tickets Exchange the accessKey for a short-lived, single-use socket ticket. **Speech to Text · Real-time** · Workflow: [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) Issues a short-lived ticket for one owned session so a browser can open the socket without exposing the long-lived key in a URL. The ticket is single-use and bound to the owner and the session; a reconnect requests a fresh one. A replayed or expired ticket is refused at the handshake. ### Path The session to stream to. ### Header API key for this REST request. Keep it on your backend in customer-facing applications; return only the session and ticket to the browser. Never put the API key in the socket URL. ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The public ticket id (`rtt_...`). The bound session. The socket path to connect. The ticket lifetime in seconds. The plaintext ticket. It is returned exactly once; only its hash is stored. ```js theme={null} const ticket = await rest('POST', `/sessions/${sessionId}/tickets`); const url = new URL(apiBase + ticket.streamUrl); url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:'; url.searchParams.set('ticket', ticket.ticket); const socket = new WebSocket(url); ``` # Create a transcription Source: https://wiz-myvocal.mintlify.app/api-reference/stt/createTranscription POST https://api.myvocal.ai/sound_clone/api/v1/stt/transcriptions Submit an uploaded file or a public media URL, quote and reserve Characters, and start the task. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) Submits one transcription from an `uploadId` or a public `mediaUrl`. The call quotes the work, reserves Characters and starts the asynchronous task in a single request. ### Header Your API key. See [Authentication](/api-reference/authentication). Binds this request. The same key and the same body return the same task; the same key with a different body is refused as `IDEMPOTENCY_CONFLICT`. ### Body An upload from `POST /uploads`. Use exactly one of `uploadId` or `mediaUrl`. A public `http`/`https` URL. The server fetches it over a real connection and re-checks every redirect; private, loopback, link-local and cloud-metadata addresses are refused. There is no domain or port allowlist. A failure reports `details.reason` (`DESTINATION_NOT_ALLOWED`, `SOURCE_REFUSED`, `SOURCE_UNAVAILABLE`, `SOURCE_UNREACHABLE`, `TOO_MANY_REDIRECTS` or `UNSUPPORTED_TYPE`) and, when the host answered, `details.sourceStatus`; see [public media URLs](/guides/stt-batch-quickstart#public-media-urls). Which audio track to transcribe. Required when the source contains more than one audio track; use the `index` from the upload's `media.audioTracks`. The spoken language, or omit for automatic detection. The hint is echoed as `languageHint`; it is never reported as the detected language. A title for the History row. Optional model identifier; defaults to `myvocal_stt_v1`. Processing options: `separateSpeakers`, `maxSpeakerCount`, `alignmentLevel`, `entityCategories`, `redactCategories`, `redactionStyle`, `rewriteInstruction`, `removeDisfluencies`, `identifyConversationRoles`, `vocabularyHints`, `separateChannels`, `channelResultMode`, `exportFormats`, `inputEncoding`, `processingContentStorage` and more. Option combinations that the model does not support are refused at submit with `INPUT_INVALID` rather than silently dropped. Completion notifications are options too: `options.notifyOnCompletion` (`true` to enable), `options.notifyUrl` (a public URL MyVocal posts the signed event to), `options.clientMetadata` (opaque caller data echoed back) and `options.notificationSigningSecret` (the write-only HMAC key). Polling stays the authoritative result. See [capabilities](/api-reference/stt/capabilities) for the live list. When `true`, this call waits for a terminal state inside the same request. The wait budget in milliseconds. If the task is still running at the budget, the request returns the task with its identity; it is not cancelled. ## Batch options All fields below belong inside `options`. Omit fields you do not need. | Field | Type and accepted values | | - | - | | `rewriteInstruction` | String, at most 2000 characters | | `includeSoundEvents` | Boolean | | `separateSpeakers` | Boolean; default `true` for single-channel processing | | `maxSpeakerCount` | Integer, 1–32 | | `speakerMergeSensitivity` | Number, 0.1–0.4; requires speaker separation and no `maxSpeakerCount` | | `alignmentLevel` | `none`, `word` (default), `character` | | `inputEncoding` | `other` (default, prepared container audio), `pcm_s16le_16` (converted 16 kHz mono PCM) | | `samplingTemperature` | Number, 0–2 | | `randomSeed` | Non-negative integer | | `separateChannels` | Boolean; preserve and transcribe channels separately | | `channelResultMode` | `separate` or `combined` | | `entityCategories` | Array, at most 32 strings; tested examples include `pii`, `phi`, `pci`, `all`, `name` | | `redactCategories` | Array, at most 32 strings; subset of `entityCategories` | | `redactionStyle` | `redact`, `replace`, `mask`; requires `redactCategories` | | `removeDisfluencies` | Boolean | | `identifyConversationRoles` | Boolean; requires speaker separation | | `vocabularyHints` | Array, at most 1000 strings, each at most 128 characters | | `processingContentStorage` | Boolean; see [storage limitations](/guides/stt-availability#speaker-matching-and-storage-requests) | | `exportFormats` | Array of supported [download formats](/api-reference/stt/downloadTranscription) to pre-generate at completion; every format stays downloadable | | `exportOptions` | Array of per-format objects, described below | | `notifyOnCompletion` | Boolean; a notification is sent when `notifyUrl` is present unless this is `false`; `true` requires `notifyUrl` | | `notifyUrl` | Public HTTP(S) URL | | `clientMetadata` | Object, at most two levels and 16 KB | | `notificationSigningSecret` | Write-only signing secret; see [notifications](/guides/stt-batch-quickstart#completion-notifications) | ### Option combinations * `rewriteInstruction` cannot be combined with entity detection, redaction or `separateChannels`. * Multi-channel processing does not separate speakers. Do not combine `separateChannels` with `maxSpeakerCount`, `speakerMergeSensitivity`, `identifyConversationRoles` or `pcm_s16le_16` input. The selected audio track can have at most five channels for transcription. * Multi-channel `combined` results require alignment and cannot be combined with entity detection or redaction. * `matchKnownSpeakers` is unavailable. Do not request it. Each `exportOptions` entry has a required `format` and optional controls: | Field | Type / limit | | - | - | | `includeSpeakers`, `includeTimestamps` | Boolean, default `true` (the `txt` segment header shows both) | | `segmentOnSilenceLongerThanS`, `maxSegmentDurationS` | Number greater than 0 and at most 3600 seconds | | `maxSegmentChars` | Integer, 1–100000; counts the separators inserted when a segment is rebuilt | | `maxCharactersPerLine` | Integer, 1–16384; wraps at word boundaries (`srt`, `txt`) | Only relevant formats use each control; `json` is the public transcription view. An entry applies to the pre-generated file and to later downloads of that format. Without timestamps (for example `alignmentLevel: none`) SRT has no timed cues and is empty. These options do not change recognition or billing. An entity category the model rejects is detected when the task runs: the task ends `FAILED` with `INPUT_INVALID`. See [parameter errors found by the model](/guides/stt-availability#parameter-errors-found-by-the-model). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The MyVocal task id, also the History id. The correlation id for this request. `QUEUED`, `PROCESSING`, `RECONCILING`, `COMPLETED`, `PARTIAL` or `FAILED`. `myvocal_stt_v1`. `state`, `planKey`, `rateVersion`, `ratePerMinute`, `reservedCharacters`, `settledCharacters`, `releasedCharacters`, `billableCharacters` and `billableDurationMs`. Characters and durations are **JSON strings**; convert before comparing. # Create an upload Source: https://wiz-myvocal.mintlify.app/api-reference/stt/createUpload POST https://api.myvocal.ai/sound_clone/api/v1/stt/uploads Reserve a presigned multi-part upload for a Batch transcription source. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) Creates a multi-part upload. Send the parts to the returned presigned URLs, then complete the upload. The server probes the file and builds the canonical audio used for the transcription. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body The original file name. The exact file size in bytes, within the technical upload ceiling. This is the request field; the response reports the stored size as `media`/`fileSizeBytes`. Media type, for example `audio/wav`. The uploaded bytes are inspected before transcription. ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The upload id to pass to create-transcription. `UPLOADING` initially; complete the upload and read its state before submitting. Analysis can result in `READY` or `FAILED`. The required part size. How many parts to send. After the file is probed: `mediaType`, `containerLabel`, `containerDurationMs` and the `audioTracks` (each with `index`, `codec`, `channels`, `sampleRateHz`, `durationMs`, `language` and `defaultTrack`). Signed part URLs expire. Request new signatures if an upload takes long, and complete the upload before submitting the transcription. Continue with [sign a part](/api-reference/stt/signUploadPart), [complete the upload](/api-reference/stt/completeUpload) and [read the upload](/api-reference/stt/getUpload). # Delete a transcription Source: https://wiz-myvocal.mintlify.app/api-reference/stt/deleteTranscription DELETE https://api.myvocal.ai/sound_clone/api/v1/stt/transcriptions/{transcriptionId} Delete a task and its content. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) Deletes a transcription. The delete takes effect immediately for every read, and is the same delete the MyVocal workspace uses. ### Path The task to delete. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The deleted task id. Stored media, the transcript and the exports are purged; accounting rows are kept without transcript text. A result that arrives after the delete is recorded as platform loss and never revives the task or charges the account. # Download a transcription Source: https://wiz-myvocal.mintlify.app/api-reference/stt/downloadTranscription GET https://api.myvocal.ai/sound_clone/api/v1/stt/transcriptions/{transcriptionId}/download Download the result as txt, json, srt, segmented_json, html, docx or pdf. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) Returns the result as a file using MyVocal fields and formatting. Downloads use the original transcription result; later edits in the workspace do not overwrite this API result. ### Path The task to download. ### Query `txt`, `json`, `srt`, `segmented_json`, `html`, `docx` or `pdf`; `txt` when omitted. The live list is returned by [capabilities](/api-reference/stt/capabilities) as `downloadFormats`. Any listed format can be downloaded whether or not it was named in `exportFormats`; the `exportOptions` entry submitted for that format applies. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response The file bytes with `Content-Disposition: attachment` and `Cache-Control: no-store`. `txt` is one block per segment: a header with the time range (timed segments only) and the speaker label, then the text; `includeTimestamps: false` / `includeSpeakers: false` remove those header parts. `json` is the bare transcription view (no `code`/`message`/`data` envelope); `srt` contains timed segments only, so an untimed result gives an empty file. The other formats are the rendered exports. Reading or re-downloading is free. Only `COMPLETED` tasks can be downloaded; any other status, including the terminal `PARTIAL`, returns `RESULT_NOT_READY`. Read a `PARTIAL` task's confirmed text from [Get a transcription](/api-reference/stt/getTranscription). An unsupported format returns `EXPORT_FORMAT_UNAVAILABLE`. Ownership is re-checked on every request. # Finish a real-time session Source: https://wiz-myvocal.mintlify.app/api-reference/stt/finishSession POST https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/finish Flush the tail, settle once and complete the task. **Speech to Text · Real-time** · Workflow: [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) Finishes a session: the server stops accepting new audio, flushes the trailing segment, waits for the final result, settles the charge once and completes the task. A repeated finish returns the same task and never charges twice. The response arrives when the result is closed; you do not have to guess a waiting time. After the last final line, finish also waits, line by line, for the supplements you requested (alignment unless `includeAlignment` is `false`, `entityCategories`, `rewriteInstruction`, and the detected language when `includeDetectedLanguage` is `true`) and returns as soon as none is outstanding, at most about **8 seconds**, and never past the session's recovery window. A requested supplement that has not arrived by then is reported, not waited for indefinitely: the session gets a `SUPPLEMENT_NOT_RECEIVED` notice listing `supplements` and the affected `lineIds` (lines missing the same kinds share a notice), and an edit that never arrived makes the task's `revisionStatus` `FAILED` with `revisionErrorCode` `REVISION_NOT_RECEIVED`. An entities result with no entities counts as arrived; on the socket it is a `transcript.entities` event with an empty list. The audio outcome and the charge do not depend on supplements. ### Path The session to finish. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body The client's confirmed capture length in samples. The decimal string form is the contract form; a JSON number is accepted for convenience. It marks a transport gap when it exceeds what the server received and never changes the charge. ### Response The same session view as [Get a real-time session](/api-reference/stt/getSession), with the terminal `status` and the final `usage`. The task is now in the shared History. A plain disconnect is not a successful finish. Use this endpoint (or the `session.finish` event) so the tail is committed and the task completes. # Get a real-time session Source: https://wiz-myvocal.mintlify.app/api-reference/stt/getSession GET https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions/{sessionId} Read the live state, usage and lines of a real-time session. **Speech to Text · Real-time** · Workflow: [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) Returns one owned session. This is also the reconnect read: it reports the current `epoch`, the received/captured cursors and whether the socket is `accepting` audio. ### Path The `sessionId` from create. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The session id. The History id. The session state while open, or the task status once closed (`COMPLETED`, `PARTIAL`, `FAILED`). The current recording segment. A `usage.updated` with `rotate: true` means start a new segment with `session.resume`; the client then sends from the new epoch. Whether the server is accepting audio for this session right now. The current temporary text for the open segment. The committed lines: `id`, `text`, `revisedText`, `languageCode`, `languageProbability` and `entities`, `words` and `characterAlignments`. Processing notices, each with `code` and `message`, for example `PROCESSING_STORAGE_NOT_APPLIED` or `SUPPLEMENT_NOT_RECEIVED` (adds `supplements`, such as `alignment`, `entities`, `revision` or `language`, and the affected `lineIds`; every listed line lacks every listed kind). The absence of a notice does not guarantee that a storage preference was applied. `estimatedCharacters`, `billableCharacters`, `elapsedMs`, `sentSamples`, `receivedSamples` and `capturedSamples`, all **decimal strings**; `accepting` is a boolean. # Get a transcription Source: https://wiz-myvocal.mintlify.app/api-reference/stt/getTranscription GET https://api.myvocal.ai/sound_clone/api/v1/stt/transcriptions/{transcriptionId} Read the task state, the transcript and the billing summary. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) Returns one transcription from the shared History. Poll this until `status` is `COMPLETED`, `PARTIAL` or `FAILED`. ### Path The `transcriptionId` returned by create, or an id from the History list. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The MyVocal task id. `QUEUED`, `PROCESSING`, `RECONCILING`, `COMPLETED`, `PARTIAL` or `FAILED`. A real-time task reports `COMPLETED` when it settled normally. `myvocal_stt_v1` for Batch, `myvocal_stt_realtime_v1` for a real-time result. The requested language, or `auto`. The detected language, only when the model returned one; otherwise `null`. It is never copied from `languageHint`. Batch results use three-letter codes (for example `eng`); real-time lines use two-letter codes (for example `en`). The analysed audio duration, as a decimal string. `null` before a result exists; a completed silent recording can have an empty transcript. `text`, `languageCode`, `languageConfidence`, `speakers`, `segments` and `channelResults`. Each segment carries `id`, `speakerId`, `channelIndex`, `startMs`, `endMs`, `text`, `timingStatus`, `tokens` and `characterAlignments`. Entities, the edited text and the per-channel results are MyVocal fields; a provider value is never exposed raw. `revisionStatus` is `NOT_REQUESTED`, `APPLIED` (edited text in `revisedText`), `EMPTY` or `FAILED` (with `revisionErrorCode`; a real-time edit that did not arrive before the session closed is `REVISION_NOT_RECEIVED`). In a `combined` channel result, a channel's `languageCode` is `null` unless the model returned a language for that channel. See [known limitations](/guides/stt-availability) for current parameter-error classification and optional-feature behavior. Stop polling terminal tasks; read `billing` to determine actual charges. The same billing summary as create. `billableCharacters` is what this task actually charges. Present only for `FAILED`: `errorCode`, `message`, `retryable`, `action` and `requestId`. # Get an upload Source: https://wiz-myvocal.mintlify.app/api-reference/stt/getUpload GET https://api.myvocal.ai/sound_clone/api/v1/stt/uploads/{uploadId} Read upload state, detected media and audio tracks. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) MyVocal API key. The upload id. The response's `data` contains `uploadId`, `state`, `fileName`, `fileSizeBytes`, `partSizeBytes`, `totalParts`, `media` and, when relevant, `errorCode`. Byte totals and duration fields use decimal strings; part counts and track indices use numbers. Once `READY`, `media.audioTracks` describes each track with `trackId`, `index`, `codec`, `channels`, `sampleRateHz`, `durationMs`, `language`, `title` and `defaultTrack`. Only the API key's owner can read the upload. # List transcriptions Source: https://wiz-myvocal.mintlify.app/api-reference/stt/listTranscriptions GET https://api.myvocal.ai/sound_clone/api/v1/stt/transcriptions List the shared History for this account. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) Lists the same History the MyVocal workspace shows. Batch and real-time results appear together. ### Query Page number, starting at `1`. Items per page. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Successful REST calls return `{ code: 1, message, data }`. The fields below are inside `data`; JSON downloads are the documented exception and return the transcript view directly. `1` for success. Result message. The current page. The page size. Total matching items. Total pages. Each entry has `transcriptionId`, `modelId`, `title`, `status`, `audioDurationMs`, `detectedLanguage`, `characters` and timestamps. `modelId` distinguishes a real-time result (`myvocal_stt_realtime_v1`) from a Batch one. # Pause a real-time session Source: https://wiz-myvocal.mintlify.app/api-reference/stt/pauseSession POST https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/pause Pause recording and commit the current segment. **Speech to Text · Real-time** · Workflow: [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) MyVocal API key. The session id. Total captured samples, after your capture queue has been flushed. Prefer a decimal string. Stop capture and send any buffered frames before pausing. The response is the [session view](/api-reference/stt/getSession). A segment can still receive its final result while the session is paused. Continue with [resume](/api-reference/stt/resumeSession), or [finish](/api-reference/stt/finishSession) when recording is over. For a WebSocket client, the equivalent event is `session.pause`. See [recovery limitations](/guides/stt-availability#real-time-disconnections-and-recovery). # Resume a real-time session Source: https://wiz-myvocal.mintlify.app/api-reference/stt/resumeSession POST https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions/{sessionId}/resume Open the next recording segment of an existing session. **Speech to Text · Real-time** · Workflow: [Real-time quickstart](/guides/stt-realtime-quickstart) · [Real-time SDKs](/sdks/stt-realtime/overview) MyVocal API key. The session id. The total capture cursor for the session, if available. Prefer a decimal string. Returns the [session view](/api-reference/stt/getSession). Use the returned `epoch` for subsequent frames and reset the new epoch's `sampleOffset` to zero; `capturedSamples` remains the total for the session. Check `accepting` before sending audio. A browser opening another socket needs a fresh single-use ticket. Resume does not restore audio lost before it reached the service. Full resume across a service replacement remains [unverified](/guides/stt-availability#real-time-disconnections-and-recovery). # Sign an upload part Source: https://wiz-myvocal.mintlify.app/api-reference/stt/signUploadPart POST https://api.myvocal.ai/sound_clone/api/v1/stt/uploads/{uploadId}/parts/{partNumber} Get the temporary URL for uploading one part. **Speech to Text · Batch** · Workflow: [Batch quickstart](/guides/stt-batch-quickstart) MyVocal API key. The upload id. One-based part number, up to `totalParts`. The response's `data` contains `partNumber`, `url` and `expiresInSeconds`. PUT the exact part bytes to `url`, **without** an `accessKey` header, and retain the returned `ETag`. Send `partSizeBytes` bytes per part except for the last part. Complete the upload with all part numbers and ETags. Request a fresh signature if a URL expires. Treat signed URLs as temporary credentials and do not log or publish them. # TTS Models & Migration Source: https://wiz-myvocal.mintlify.app/api-reference/tts/models Public model IDs, language behavior, and V2 to V3 migration guidance. Use this page as the source of truth for publicly documented TTS model IDs. ## Model overview | Model ID | Recommended usage | Languages | | - | - | - | | `myvocal_v3` | Explicit V3 request path | See the full list in [V3 Language Codes](/api-reference/tts/v3-language-codes). | | `myvocal_v3_accent_enhance` | Explicit Accent request path | 40 language codes plus `auto`. See the Accent model section below. | | `english_v2` | V2 explicit English (original accent) | English (original accent). | | `spanish_es` | V2 explicit Spanish (ES) | Spanish (ES). | | `portuguese_pt` | V2 explicit Portuguese (PT) | Portuguese (PT). | | `multilingual_v2` | V2 shared multilingual path | French, German, Arabic, Japanese, and other mapped languages. | | `spanish_la` | V2 explicit Spanish (LA) | Spanish (LA). | | `portuguese_la` | V2 explicit Portuguese (LA) | Portuguese (LA). | ## Public model ID list ```text theme={null} myvocal_v3 myvocal_v3_accent_enhance english_v2 spanish_es portuguese_pt multilingual_v2 spanish_la portuguese_la ``` ## V3 language scope * Supported language count: `98` * Excluded from support: `Kirghiz`, `Lingala` View the complete supported language and code table. ## Accent model (`myvocal_v3_accent_enhance`) The Accent model has its own language contract. It is not the same set as `myvocal_v3`. * Supported language count: `40` language codes, plus `auto`. * Omitting `language` is equivalent to `auto`. * A code outside this list is rejected with `code = 10004`. This includes plain V3 codes the Accent model does not support, such as `hmn`. * Legacy mapped enum values (for example `US_ENGLISH`) are not Accent codes. Use `en`. Accepted Accent language codes: ```text theme={null} auto zh yue en ar ru es fr pt de tr nl uk vi id ja it ko th pl ro el cs fi hi bg da he ms fa sk sv hr fil hu no sl ca nn ta af ``` Other Accent behavior: * Voices: use the compatible voices returned by `GET /sound_clone/api/v1/voices?modelId=myvocal_v3_accent_enhance`. That list includes your own compatible voices and the prebuilt voices available to your API key. A voice listed there is a selection aid, not a guarantee that a later generation will succeed. * `voiceSettings.stability`: a value inside the legal range (`0.1` to `1`) is accepted for compatibility but has no effect on this model. Out-of-range values are still rejected with `code = 10006`. * Prompt tags: inline `[tag]` prompt control is documented for `myvocal_v3`. It is not documented as equivalent for the Accent model; send plain text. * Character metering, plan limits and rates stay the same as the other TTS models. ## Default path vs explicit `modelId` * Default path: omit `modelId` and follow current V2/default mapping rules. * Explicit V3 path: set `modelId` to `myvocal_v3`. * Explicit Accent path: set `modelId` to `myvocal_v3_accent_enhance`. `English(US)` currently uses the default model path. A public explicit `modelId` for `English(US)` is not published in this phase. ## V2 to V3 migration guidance 1. Keep your V2 flow as fallback. 2. Add a feature flag for `modelId: "myvocal_v3"`. 3. Use explicit `language` if you want deterministic target language output. 4. Omit `language` for auto-detect behavior on V3. 5. Roll out with traffic slices and monitor output quality. ## Migration to the Accent model The table describes what changes when you move from the default/V2 path or from `myvocal_v3` to `myvocal_v3_accent_enhance`. | Your current request | What to change | | - | - | | Compatible voice + plain text + a language the Accent model supports | Change only `modelId` to `myvocal_v3_accent_enhance`. | | `language` omitted or `auto` | No change; both mean automatic detection. | | Legacy mapped language enum such as `US_ENGLISH` | Replace with the Accent code `en`. | | Plain V3-only code not in the Accent list (for example `hmn`) | Choose a supported Accent code and re-test, or keep using `myvocal_v3`. | | Inline `[tag]` prompt control | Send plain text for the Accent model, or keep using `myvocal_v3`. | | A voice that the Accent voice list does not return | Keep using the model you use today for that voice. | # Create speech Source: https://wiz-myvocal.mintlify.app/api-reference/tts/tts POST https://api.myvocal.ai/sound_clone/api/v1/tts Synthesize text and return the complete audio in the response body. **Text to Speech** · Workflow: [TTS quickstart](/quickstart) · Models: [TTS Models & Migration](/api-reference/tts/models) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Voice ID returned by GET /sound\_clone/api/v1/voices.
For myvocal\_v3\_accent\_enhance, use a voice returned by GET /sound\_clone/api/v1/voices?modelId=myvocal\_v3\_accent\_enhance.
Optional title for the generated record. If empty, backend uses a default title. Text to synthesize. Language selector.
Default/V2 path: required and must use existing mapped language values.
myvocal\_v3: optional. If provided, it is forwarded to upstream as language. If omitted, upstream auto-detect is used.
See supported V3 codes in V3 Language Codes (98 languages).
myvocal\_v3\_accent\_enhance: optional. Omit it (or send auto) for automatic detection. The Accent model has its own code set (40 language codes plus auto); see TTS Models & Migration. A plain V3 code the Accent model does not support (for example hmn) is rejected with code = 10004. Legacy mapped enum values such as US\_ENGLISH are not Accent codes; use en.
Optional explicit model selector.
Omit it to use the default model path.
Set myvocal\_v3 to request the V3 path.
Set myvocal\_v3\_accent\_enhance to request the Accent model path.
When the Accent model is requested but its execution path is unavailable, the response is the standard generation error envelope (code = 10003). The request is never silently served by a different model.
For advanced settings, use suggested values unless you have strong tuning needs.
a decimal in the range 0.1 to 1 inclusive, with a recommended default value of 0.7. Values below 0.1 or above 1 are rejected; no fixed step is enforced.
When your parameters are set lower, the emotional variation of the TTS audio will be more abundant. Even for the same text, the effects generated multiple times will be different. You can choose the most suitable one by generating the same text's TTS audio multiple times.
When your parameters are set higher, the emotion of the TTS audio will tend to be consistent.
Accent model note: a value inside the normal legal range (0.1 to 1) is accepted for compatibility but has no effect on myvocal\_v3\_accent\_enhance. An out-of-range value is still rejected with code = 10006.
For myvocal\_v3, the currently publicly documented stability values are:
- 0.5: natural pronunciation, closer to normal human speech.
- 1: more stable output with less variation.
For myvocal\_v3\_accent\_enhance, plain text is the supported minimal path. The inline \[tag] prompt control documented for myvocal\_v3 is not documented as equivalent, and the service does not rewrite your text. Send plain text for the Accent model. ### Prompt Control (myvocal\_v3) Reference capability source: v3.myvocal.ai. Use \[tag] in text to guide style and delivery. Basic syntax: ```text theme={null} [tag] Your text content ``` Examples: ```text theme={null} [happy] Hello everyone, welcome to MyVocal. [laughter] That was funny. ``` Representative categories: * Emotion control: `happy`, `excited`, `sad`, `angry`, `surprised` * Non-speech sounds: `laughter`, `throat clearing`, `yawning`, `shushing`, `screaming` * Sound-related effects: `breathing`, `sighing`, `gasping`, `crying`, `murmuring` Open boundary note: > The listed tags are representative examples. The model can understand a broader set of sound and emotion prompts. ### Response Success usually returns audio/mpeg. Binary audio stream payload on success. An HTTP `200` does not by itself mean the request succeeded. Read `Content-Type` before trusting the body: * `audio/*` (normally `audio/mpeg`): the audio payload described above. * any JSON content type: the standard result envelope with a non-success `code` (see Common errors below). The two paths fail differently. Before any audio is sent, a rejected or failed request is answered with the JSON envelope above. After audio has started, the connection is terminated instead of appending a JSON body, because appending JSON to a partial audio body would corrupt it. Treat a short or interrupted download as a failed request, not as a complete audio file. ```bash Default model path theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "tts-default", "text": "Hello from MyVocal default model path.", "language": "en", "voiceSettings": { "stability": 0.7 } }' \ --output output-default.mp3 ``` ```bash Explicit myvocal_v3 with language theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "tts-v3-explicit-language", "text": "[happy] Hola, this is a short V3 test.", "language": "en", "modelId": "myvocal_v3", "voiceSettings": { "stability": 0.5 } }' \ --output output-v3-explicit.mp3 ``` ```bash Explicit myvocal_v3 with auto-detect (omit language) theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "tts-v3-auto-detect", "text": "[happy] Hola, este es un test para auto detect.", "modelId": "myvocal_v3", "voiceSettings": { "stability": 0.5 } }' \ --output output-v3-auto.mp3 ``` ```bash Explicit myvocal_v3_accent_enhance theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "text": "Hello from the Accent model.", "modelId": "myvocal_v3_accent_enhance" }' \ --output output-accent.mp3 ``` ```text 200 Success theme={null} audio/mpeg stream (binary) ``` ```json 200 Fail theme={null} { "code": 10004, "message": "Invalid language option.", "data": null } ``` ### Common errors * `Invalid language option.` (`code = 10004`): non-V3/default path is missing or using an unsupported `language` value; or the Accent model received a code outside its own language list. * `VOICE_NOT_FOUND` (`code = 10005`): `voiceId` is invalid or not available under this API key. * `Invalid stability option.` (`code = 10006`): `voiceSettings.stability` is outside the legal range. * `code = 10003`: the Accent model path was requested but its execution path is unavailable. The request is not silently served by another model. * `code = -1`: upstream or backend failed to complete generation. # Stream speech Source: https://wiz-myvocal.mintlify.app/api-reference/tts/ttsStream POST https://api.myvocal.ai/sound_clone/api/v1/tts/stream Synthesize text and return the audio as a streaming response. **Text to Speech** · Workflow: [TTS quickstart](/quickstart) · Models: [TTS Models & Migration](/api-reference/tts/models) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Voice ID returned by GET /sound\_clone/api/v1/voices.
For myvocal\_v3\_accent\_enhance, use a voice returned by GET /sound\_clone/api/v1/voices?modelId=myvocal\_v3\_accent\_enhance.
Optional title for the generated record. Text to synthesize. Language selector.
Default/V2 path: required and must use existing mapped language values.
myvocal\_v3: optional. If provided, it is forwarded to upstream as language. If omitted, upstream auto-detect is used.
See supported V3 codes in V3 Language Codes (98 languages).
myvocal\_v3\_accent\_enhance: optional. Omit it (or send auto) for automatic detection. The Accent model has its own code set (40 language codes plus auto); see TTS Models & Migration. A plain V3 code the Accent model does not support (for example hmn) is rejected with code = 10004. Legacy mapped enum values such as US\_ENGLISH are not Accent codes; use en.
Optional explicit model selector.
Omit it to use the default model path.
Set myvocal\_v3 to request the V3 path.
Set myvocal\_v3\_accent\_enhance to request the Accent model path.
When the Accent model is requested but its execution path is unavailable, the response is the standard generation error envelope (code = 10003). The request is never silently served by a different model.
For advanced settings, use suggested values unless you have strong tuning needs.
a decimal in the range 0.1 to 1 inclusive, with a recommended default value of 0.7. Values below 0.1 or above 1 are rejected; no fixed step is enforced.
When your parameters are set lower, the emotional variation of the TTS audio will be more abundant. Even for the same text, the effects generated multiple times will be different. You can choose the most suitable one by generating the same text's TTS audio multiple times.
When your parameters are set higher, the emotion of the TTS audio will tend to be consistent.
Accent model note: a value inside the normal legal range (0.1 to 1) is accepted for compatibility but has no effect on myvocal\_v3\_accent\_enhance. An out-of-range value is still rejected with code = 10006.
For myvocal\_v3, the currently publicly documented stability values are:
- 0.5: natural pronunciation, closer to normal human speech.
- 1: more stable output with less variation.
For myvocal\_v3\_accent\_enhance, plain text is the supported minimal path. The inline \[tag] prompt control documented for myvocal\_v3 is not documented as equivalent, and the service does not rewrite your text. Send plain text for the Accent model. ### Prompt Control (myvocal\_v3) Reference capability source: v3.myvocal.ai. Use \[tag] in text to guide style and delivery. Basic syntax: ```text theme={null} [tag] Your text content ``` Examples: ```text theme={null} [happy] Hello everyone, welcome to MyVocal. [laughter] That was funny. ``` Representative categories: * Emotion control: `happy`, `excited`, `sad`, `angry`, `surprised` * Non-speech sounds: `laughter`, `throat clearing`, `yawning`, `shushing`, `screaming` * Sound-related effects: `breathing`, `sighing`, `gasping`, `crying`, `murmuring` ### Response Success usually returns audio/mpeg. Binary audio stream payload. An HTTP `200` does not by itself mean the request succeeded. Read `Content-Type` before trusting the body: * `audio/*` (normally `audio/mpeg`): the audio payload described above. * any JSON content type: the standard result envelope with a non-success `code` (see Common errors below). The two paths fail differently. Before any audio is sent, a rejected or failed request is answered with the JSON envelope above. After audio has started, the connection is terminated instead of appending a JSON body, because appending JSON to a partial audio body would corrupt it. Treat a short or interrupted download as a failed request, not as a complete audio file. ```bash Default model path theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/stream' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "tts-stream-default", "text": "Hello from MyVocal streaming endpoint.", "language": "en", "voiceSettings": { "stability": 0.7 } }' \ --output output-default.mp3 ``` ```bash Explicit myvocal_v3 with language theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/stream' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "tts-stream-v3-explicit-language", "text": "[happy] Hola, this is a short V3 streaming test.", "language": "en", "modelId": "myvocal_v3", "voiceSettings": { "stability": 0.5 } }' \ --output output-v3-explicit.mp3 ``` ```bash Explicit myvocal_v3 with auto-detect (omit language) theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/stream' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "tts-stream-v3-auto-detect", "text": "[happy] Hola, este es un test para auto detect.", "modelId": "myvocal_v3", "voiceSettings": { "stability": 0.5 } }' \ --output output-v3-auto.mp3 ``` ```bash Explicit myvocal_v3_accent_enhance theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/stream' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "text": "Hello from the Accent model.", "modelId": "myvocal_v3_accent_enhance" }' \ --output output-accent.mp3 ``` ```text 200 Success theme={null} audio/mpeg stream (binary) ``` ```json 200 Fail theme={null} { "code": 10004, "message": "Invalid language option.", "data": null } ``` ### Common errors * `Invalid language option.` (`code = 10004`): non-V3/default path is missing or using an unsupported `language` value; or the Accent model received a code outside its own language list. * `VOICE_NOT_FOUND` (`code = 10005`): `voiceId` is invalid or not available under this API key. * `Invalid stability option.` (`code = 10006`): `voiceSettings.stability` is outside the legal range. * `code = 10003`: the Accent model path was requested but its execution path is unavailable. The request is not silently served by another model. * `code = -1`: upstream or backend failed to complete generation. # V3 Language Codes Source: https://wiz-myvocal.mintlify.app/api-reference/tts/v3-language-codes Supported language codes for myvocal_v3. ## Summary * Supported languages: `98` * Excluded from support: `Kirghiz, Lingala` Only use language codes listed on this page for `myvocal_v3`. ## Full list | Language | Code | | - | - | | Afrikaans | `af` | | Arabic | `ar` | | Armenian | `hy` | | Assamese | `as` | | Azerbaijani | `az` | | Belarusian | `be` | | Bengali | `bn` | | Bosnian | `bs` | | Bulgarian | `bg` | | Catalan | `ca` | | Cebuano | `ceb` | | Chichewa | `ny` | | Croatian | `hr` | | Czech | `cs` | | Danish | `da` | | Dutch | `nl` | | English | `en` | | Estonian | `et` | | Filipino | `fil` | | Finnish | `fi` | | French | `fr` | | Galician | `gl` | | Georgian | `ka` | | German | `de` | | Greek | `el` | | Gujarati | `gu` | | Hausa | `ha` | | Hebrew | `he` | | Hindi | `hi` | | Hungarian | `hu` | | Icelandic | `is` | | Indonesian | `id` | | Irish | `ga` | | Italian | `it` | | Japanese | `ja` | | Javanese | `jv` | | Kannada | `kn` | | Kazakh | `kk` | | Korean | `ko` | | Latvian | `lv` | | Lithuanian | `lt` | | Luxembourgish | `lb` | | Macedonian | `mk` | | Malay | `ms` | | Malayalam | `ml` | | Mandarin Chinese | `zh` | | Marathi | `mr` | | Nepali | `ne` | | Norwegian | `no` | | Pashto | `ps` | | Persian | `fa` | | Polish | `pl` | | Portuguese | `pt` | | Punjabi | `pa` | | Romanian | `ro` | | Russian | `ru` | | Serbian | `sr` | | Sindhi | `sd` | | Slovak | `sk` | | Slovenian | `sl` | | Somali | `so` | | Spanish | `es` | | Swahili | `sw` | | Swedish | `sv` | | Tamil | `ta` | | Telugu | `te` | | Thai | `th` | | Turkish | `tr` | | Ukrainian | `uk` | | Urdu | `ur` | | Vietnamese | `vi` | | Welsh | `cy` | | Albanian | `sq` | | Basque | `eu` | | Esperanto | `eo` | | Fijian | `fj` | | Haitian Creole | `ht` | | Khmer | `km` | | Lao | `lo` | | Mongolian | `mn` | | Sinhala | `si` | | Tajik | `tg` | | Uzbek | `uz` | | Zulu | `zu` | | Yoruba | `yo` | | Igbo | `ig` | | Amharic | `am` | | Aymara | `ay` | | Tigrinya | `ti` | | Tswana | `tn` | | Xhosa | `xh` | | Burmese | `my` | | Maori | `mi` | | Samoan | `sm` | | Tonga | `to` | | Navajo | `nv` | | Hmong | `hmn` | | Kurdish | `ku` | # Get account information Source: https://wiz-myvocal.mintlify.app/api-reference/user/getInfo GET https://api.myvocal.ai/sound_clone/api/v1/user/info Return the plan, subscription status and voice and Character quotas of the account that owns the API key. **Getting started** · Use this read-only call to verify your key: [First API request](/guides/get-started) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. Your current subscription plan.
Your current subscription status:
If you haven't cancel your subsciption, the status will be "active",
If you have cancelled your subcription, the status will be "cancellation upon expiration" before the subscription expired.
If you haven't cancelled your subscription, this parameter means the countdown days for your plan benefits to be updated.
If you have cancelled your subscription, this parameter means the countdown days for your plan to be downgraded to a free user.
The number of custom voices you created through the website or API. The maximum number of custom voices you can create with your subscription plan. The number of TTS characters you have used within your subscription plan. The maximum number of TTS characters within your subscription plan. The number of TTS characters you have used without your subscription plan. The number of TTS characters you have purchased without your subscription plan.
```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/user/info' \ --header 'accessKey: xxxx' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": { "plan": "Business", "status": "active", "resetInDays": 2, "benefit": { "usedVoices": 146, "totalVoices": 150, "usedMonthlyChars": 3498604, "totalMonthlyChars": 3500000, "usedOrderChars": 0, "totalOrderChars": 0 } } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Create a Cover voice Source: https://wiz-myvocal.mintlify.app/api-reference/voice/addCoverVoice POST https://docs.myvocal.ai/sound_clone/api/v1/voices/vc Clone a custom AI Cover voice from your recordings. Training finishes asynchronously and is reported to your callback URL. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) The training result is delivered to your `callbackUrl`; see [Cover callbacks](/callback) (`TRAIN_COVER_SPEAKER`). The interactive playground on this page cannot send file uploads. This is a limitation of the documentation playground, not of the API. Send the `multipart/form-data` request to `https://api.myvocal.ai/sound_clone/api/v1/voices/vc` from your own code or an HTTP tool, as in the request example. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Please do not exceed 32 characters in length.

Please provide mp3/wav/m4a files.

A single file cannot exceed 10MB, and up to 25 files can be uploaded.

Please ensure that the total effective duration of the audio (including the parts with human voice, excluding the silent parts) is longer than 1 minute.

To receive the audio returned after processing is completed. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. When the request is successfully sent, a webhookId will be synchronously returned. The same information will also be called back in the callbackUrl, which is used to correlate the request and the response. ```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices/vc' \ --header 'accessKey: xxx' \ --form 'files=@"xxx/xxx.mp3"' \ --form 'name="111"' \ --form 'callbackUrl="http://www.google.com"' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": { "webhookId": "1701406584rkzy91" } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Create a TTS voice Source: https://wiz-myvocal.mintlify.app/api-reference/voice/addTTSVoice POST https://docs.myvocal.ai/sound_clone/api/v1/voices/tts Clone a custom Text to Speech voice from your recordings. The voiceId is returned in the response. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) The interactive playground on this page cannot send file uploads. This is a limitation of the documentation playground, not of the API. Send the `multipart/form-data` request to `https://api.myvocal.ai/sound_clone/api/v1/voices/tts` from your own code or an HTTP tool, as in the request example. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Please do not exceed 32 characters in length. Please provide mp3/wav/m4a files. A single file cannot exceed 10MB, and up to 25 files can be uploaded. ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. When you need to use TTS or other features, voiceId needs to be provided. ```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices/tts' \ --header 'accessKey: xxx' \ --form 'files=@"xxx/xxx.mp3"' \ --form 'name="111"' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": { "id": "7812" } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Delete a voice Source: https://wiz-myvocal.mintlify.app/api-reference/voice/delete DELETE https://api.myvocal.ai/sound_clone/api/v1/voices/{id} Delete a custom voice by its voiceId. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path Your voiceId ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. ```bash Example Request theme={null} curl --location --request DELETE 'https://api.myvocal.ai/sound_clone/api/v1/voices/7812' \ --header 'accessKey: xxx' \ --header 'Content-Type: application/json' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Improve a Cover voice Source: https://wiz-myvocal.mintlify.app/api-reference/voice/editCoverVoice PUT https://docs.myvocal.ai/sound_clone/api/v1/voices/vc/{voiceId} Upload more recordings to improve a custom AI Cover voice. The result is reported to your callback URL. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) The result is delivered to your `callbackUrl`; see [Cover callbacks](/callback) (`EDIT_COVER_SPEAKER`). The interactive playground on this page cannot send file uploads. This is a limitation of the documentation playground, not of the API. Send the `multipart/form-data` request to `https://api.myvocal.ai/sound_clone/api/v1/voices/vc/{voiceId}` from your own code or an HTTP tool, as in the request example. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Your voiceId To receive the audio returned after processing is completed.

Please provide mp3/wav/m4a files.

A single file cannot exceed 10MB, and up to 25 files can be uploaded.

Please ensure that the total effective duration of the audio (including the parts with human voice, excluding the silent parts) is longer than 1 minute.

### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. Includes specific data. When the request is successfully sent, a webhookId will be synchronously returned. The same information will also be called back in the callbackUrl, which is used to correlate the request and the response. ```bash Example Request theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices/vc/123' \ --header 'accessKey: xxx' \ --form 'files=@"xxx/xxx.mp3"' \ --form 'callbackUrl="111"' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", "data": { "webhookId": "1701406584rkzy91" } } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Improve a TTS voice Source: https://wiz-myvocal.mintlify.app/api-reference/voice/editTTSVoice PUT https://docs.myvocal.ai/sound_clone/api/v1/voices/tts/{voiceId} Upload more recordings to improve a custom Text to Speech voice. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) The interactive playground on this page cannot send file uploads. This is a limitation of the documentation playground, not of the API. Send the `multipart/form-data` request to `https://api.myvocal.ai/sound_clone/api/v1/voices/tts/{voiceId}` from your own code or an HTTP tool, as in the request example. ### Header Your API key. See [Authentication](/api-reference/authentication). ### Body Your voiceId Please provide mp3/wav/m4a files. A single file cannot exceed 10MB, and up to 25 files can be uploaded (including files provided when you add voice). ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. ```bash Example Request theme={null} curl --location --request PUT 'https://api.myvocal.ai/sound_clone/api/v1/voices/tts/7812' \ --header 'accessKey: xxx' \ --form 'files=@"xxx/xxx.mp3"' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # List voices Source: https://wiz-myvocal.mintlify.app/api-reference/voice/list GET https://api.myvocal.ai/sound_clone/api/v1/voices Return voices available to the current API key. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Query Optional model filter.
Omit it to keep the current unfiltered response.
Set it to myvocal\_v3\_accent\_enhance to return the voices compatible with the Accent model: your own compatible voices plus the prebuilt voices available to your API key.
The filtered list is a selection aid. A voice appearing in it is not a guarantee that a later generation will succeed, and the generation call checks the current state again.
### Response `1` for success. Backend message for success or failure context. Voice objects available under the current API key. Voice ID. Voice display name.
cloned: created from uploaded or recorded audio.
designed: created with voice design.
text-to-speech or ai-cover. web or api. Number of source files associated with the voice. Total file size value reported by backend.
`GET /voices` does not return per-voice `supportedModels`. Do not rely on this endpoint alone to decide whether a voice is guaranteed to work with `myvocal_v3`. `GET /voices` does not return per-voice `supportedModels`. Do not rely on this endpoint alone to decide whether a voice is guaranteed to work with `myvocal_v3_accent_enhance` either; the same limitation applies to the Accent-filtered list. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices' \ --header 'accessKey: ' ``` ```bash Accent-compatible voices theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices?modelId=myvocal_v3_accent_enhance' \ --header 'accessKey: ' ``` ```json 200 Success theme={null} { "code": 1, "message": "Success", "data": [ { "id": "7789", "name": "FirstClonedVoice", "type": "cloned", "feature": "text-to-speech", "channel": "web", "fileCount": 2, "totalFileSize": 582944 } ] } ``` ```json 200 Fail theme={null} { "code": -1, "message": "error msg" } ``` # Rename a voice Source: https://wiz-myvocal.mintlify.app/api-reference/voice/updateVoiceName PUT https://api.myvocal.ai/sound_clone/api/v1/voices/rename/{id} Change the display name of a voice. **Voice cloning** · Workflow: [How to use voices](/guides/voice-quickstart) ### Header Your API key. See [Authentication](/api-reference/authentication). ### Path Your voiceId ### Body Your new voice name ### Response Indicates whether the call was successful. 1 if successful. When an exception occurs, specific exception information will be provided in the message. ```bash Example Request theme={null} curl --location --request PUT 'https://api.myvocal.ai/sound_clone/api/v1/voices/rename/7812' \ --header 'accessKey: xxx' \ --header 'Content-Type: application/json' \ --data '{ "name": "rename" }' ``` ```json 200(success) theme={null} { "code": 1, "message": "Success", } ``` ```json 200(fail) theme={null} { "code": -1, "message": "error msg", } ``` # Cover callbacks Source: https://wiz-myvocal.mintlify.app/callback How AI Cover and Cover voice requests deliver their result to your callbackUrl, and which other products use a different mechanism. **AI Cover** · Workflow: [AI Cover quickstart](/guides/cover-quickstart) This callback protocol applies only to the AI Cover flows that take a `callbackUrl`: | `webhookType` | Started by | | - | - | | `TRAIN_COVER_SPEAKER` | [Create a Cover voice](/api-reference/voice/addCoverVoice) | | `EDIT_COVER_SPEAKER` | [Improve a Cover voice](/api-reference/voice/editCoverVoice) | | `COVER_SONG` | [Generate a cover](/api-reference/cover/cover) | These requests take longer to process, so the result is delivered asynchronously to the callback URL you provide in the request. Other products do not use this protocol: * **Speech to Text — Batch:** poll the transcription. The optional completion notification has its own signed (HMAC) contract; see [STT completion notifications](/guides/stt-batch-quickstart#completion-notifications). * **Speech to Text — Real-time:** results arrive as WebSocket events on the session's socket. They are not HTTP callbacks; see the [real-time quickstart](/guides/stt-realtime-quickstart). * **Text to Music and Interpretation:** poll-based; no callback (see below). * **Text to Speech, TTS voices and account information:** the result is in the HTTP response. ### Request

Please provide a callback URL and ensure that the callback URL provided is consistent across different scenarios.

Please make sure that the url you provide is accessible to the public network and that the request type is POST.

If the callback URL varies, there may be inconsistencies between the callback URL used during the callback and the callback URL you provided at the time of the request.

### Response When an asynchronous request is sent successfully, we will immediately provide a webhookId. When a callback is made, this webhookId will also be included in the callback URL. You can use the webhookId to associate the request with the callback. When the request is successfully sent, a webhookId will be synchronously returned. The same information will also be called back in the callbackUrl, which is used to correlate the request and the response.
TRAIN\_COVER\_SPEAKER: Add an AI Cover Voice
EDIT\_COVER\_SPEAKER: Improve an AI Cover Voice
COVER\_SONG: Create an AI Cover song
The status of this request
SUCCESS: this request is success
FAILURE: this request is fail
Human-readable result summary. business data ### Samples ```json 200(success) theme={null} { "webhookId":"1700189306ffhdkejwcsk2", "webhookType":"TRAIN_COVER_SPEAKER", "status":"SUCCESS", "summary":"Clone training success.", "data":{ "id":"100" } } ``` ```json 200(fail) theme={null} { "webhookId":"1700189306ffhdkejwcsk2", "webhookType":"TRAIN_COVER_SPEAKER", "status":"FAILURE", "summary":"Clone training failed." } ``` ## Text-to-Music and Interpretation The callback and `webhookId` mechanism on this page applies to the AI Cover flows listed above (`TRAIN_COVER_SPEAKER`, `EDIT_COVER_SPEAKER`, `COVER_SONG`). **Text-to-Music and Interpretation do not use callbacks and never call your webhook.** They are poll-based: create the project, then poll the project/job endpoints until the resource reaches a terminal state. Neither product takes a callback URL parameter, and neither returns a `webhookId`. If you are integrating Text-to-Music or Interpretation, implement polling instead — see [Async jobs, polling and retries](/guides/async-jobs-and-retries). Poll the project until `projectStatus` is `READY`, then download the MP3. Poll the project until every target is `READY`, then play or export it. # Async jobs, polling and retries Source: https://wiz-myvocal.mintlify.app/guides/async-jobs-and-retries For Text-to-Music and Interpretation: how jobs report progress, and how to poll, time out and recover safely. **Applies to Text-to-Music and Interpretation.** Both are asynchronous and **poll-based**: a create call returns identifiers immediately; you then poll the project or job endpoints until the resource reaches a terminal state. Neither product uses callbacks or webhooks. Other products report asynchronous results differently: | Product | Mechanism | Where it is described | | - | - | - | | Text to Music, Interpretation | Poll the project/job | This page | | Speech to Text — Batch | Poll the transcription; optional signed completion notification | [Batch quickstart](/guides/stt-batch-quickstart#completion-notifications) | | Speech to Text — Real-time | WebSocket events on the session, then `finish` | [Real-time quickstart](/guides/stt-realtime-quickstart) | | AI Cover, Cover voice creation and improvement | Callback to your `callbackUrl` | [Cover callbacks](/callback) | ## The shape of an async call 1. **Create** with an `Idempotency-Key`. You receive a stable resource identifier (project, job, target, upload, export). 2. **Poll** the read endpoints for that resource. 3. **Act** when the resource is terminal: play, download or export — or read the failure and recover. Always keep the returned identifiers. They are the only reliable way to recover after a timeout, a crash or a lost response. ## Terminal states ### Text-to-Music Read the project with `GET /sound_clone/api/v1/music/projects/{projectId}`. | Field | Terminal values | | - | - | | `projectStatus` | `READY` (song available), `DELETED`; failures are reported through `lastFailure` | | job `status` | `READY`, `FAILED`, `RELEASED` (`terminal` is `true` for exactly these) | `RECOVERY_REQUIRED` is **not** terminal. It means the outcome still needs reconciliation: keep the identifiers and keep querying. It is neither a failure nor a refund. ### Interpretation Read the project with `GET /sound_clone/api/v1/interpretation/projects/{projectId}`. | Field | Values | | - | - | | `summaryState` | `DRAFT`, `PROCESSING`, `PARTIAL_READY`, `READY`, `FAILED` | | `targets[].state` | `QUEUED`, `PREPARING`, `TRANSLATING`, `EXPORTING`, `RECONCILING`, `READY`, `FAILED_RELEASED` | `READY` and `FAILED_RELEASED` are the per-target end states. `summaryState` is a roll-up: `PARTIAL_READY` means some languages are done and some are not — it is a normal interim state, not an error. `RECONCILING` (on a target, a job or a logical generation) means the result is still being reconciled. Treat it as "still working", never as a failure or as an already-released reservation. ### Exports (Interpretation) An export is its own small async resource: `PROCESSING`, `RETRY` or `READY`. `PROCESSING` and `RETRY` are transient; keep polling the **same** `exportId`. `READY` is the only state that has a download URL. In particular, do not treat `RETRY` as a terminal failure and never start a new paid generation to work around a slow export. ## Choosing a poll interval * `nextPollAfterMs` is the field meant for this. On Interpretation it is currently always `null`, because the service does not publish a suggested interval yet. Handle `null` explicitly. * Use a bounded interval with jitter — 2–5 seconds is a reasonable starting point for both products — and an overall bounded wait. * Do not poll in a tight loop, and do not poll a resource you can no longer act on. ``` delay = nextPollAfterMs ?? randomBetween(2000, 5000) // jitter avoids synchronized bursts wait at most MAX_WAIT for the resource to become terminal ``` ## Recovering from a timeout A timeout is a **client-side** decision. It does not cancel the server-side work and it does not mean the work failed. When you time out: 1. Report the resource identifiers (`projectId`, `jobId`, `targetId`, `exportId`) to the user or log them. 2. Stop; keep the identifiers. 3. Resume later by querying the same identifiers — the work continues server-side. Do **not**: * Treat a timeout as a failure and issue a refund or a release. Only the real ledger state can tell you what happened to the reservation. * Resubmit a paid generation because you lost the response. That is what the identifiers and the idempotency key are for. ## Idempotency and replay `Idempotency-Key` is required on the create/accept endpoints. Use a unique printable ASCII value of 16–64 characters per distinct operation, and persist it together with the request body summary and the returned identifiers, so a restart can resume instead of starting over. Important: **a replay is not guaranteed to return the first response.** | Product | Behaviour | | - | - | | Text-to-Music | A replay re-reads the current resource. `POST /projects` may return a full project detail where the first response returned `{projectId, projectStatus, job}`; `POST /generations` and `/arrangement/regenerate` may return a job read model instead of the original create payload. | | Interpretation | A replay re-reads the current acceptance; target and job state may already have advanced. The same quote presented with a different key also reuses the existing acceptance, before any price re-check, so it is not charged twice. | Recovery rule for both: **use the stable identifier to re-query** (`GET /projects/{id}`, `GET /jobs/{id}`) rather than assuming the replay equals the first response. Conflicts are different from replays: * Music: same key with a different body → `code = 47008`. * Interpretation: same key with a different body → `code = 47111`. A conflict means something already happened for that key. Never silently switch to a new key to force the call through; re-read the resource to find out what the server already did. ## Transient versus terminal failures Not every failure should end your flow: | Signal | Meaning | What to do | | - | - | - | | Music `47010`, Interpretation error while a target is mid-flight | An operation is already in progress | Wait and re-query; do not start a parallel paid operation | | Music `47011`, Interpretation `47122` | Temporarily unavailable | Bounded retry with backoff | | Music `47006` / `47007`, Interpretation `47108` / `47109` | Quote expired or no longer valid | Re-quote, then generate again (see below) | | Music `47013` / `47014`, Interpretation `47118` | Generation failed / output invalid, reservation released | Business failure; report it and offer a retry if one is supported | | Music `47017` | Delete conflicted with an in-flight job | The job is not cancelled; wait for it, then decide | | Interpretation `47112` / `47113` | Reconciling / export recovering | Keep polling; these are not failures | ## Expired or consumed quotes * A quote has a time-to-live (`quoteTtlSeconds`, normally 600 seconds). * Text-to-Music consumes a quote when it is used: re-submitting the same `quoteId` with a different key is rejected with `47007`. * Interpretation **reuses** the acceptance for an already-accepted quote instead of charging again. So when a generation attempt fails before any work starts, re-quote and try again. When it fails after the quote was accepted, query the existing project/job before doing anything else — you may already have a resource in progress. ## Retrying a failed Interpretation target Only a target in `FAILED_RELEASED` with `action = "RETRY"` may be retried: 1. `GET /projects/{projectId}/targets/{targetId}/retry-plan` — the server decides the amount and the next reservation cycle. 2. `POST /projects/{projectId}/targets/{targetId}/retry` with the plan's `nextReservationCycle`, `characters` and `rateVersion`. Those amount fields are a **confirmation of the server's plan**, not client-side pricing: never compute or adjust the price yourself. `OPERATION_RETRY` is replay-safe, so a retried POST with the same key does not create a second charge. ## Regenerating a Text-to-Music arrangement If the arrangement is not what you wanted, `POST /projects/{projectId}/arrangement/regenerate` with `{ "expectedVersion": n }` requests a new arrangement (idempotent). An `expectedVersion` mismatch is rejected with `47016`; re-read the project and retry with the current version. ## A sample polling loop ```text theme={null} create -> save projectId (+ jobId) loop until terminal or MAX_WAIT: sleep(delay) detail = GET /projects/{projectId} if terminal: break delay = nextPollAfterMs ?? jittered(2000..5000) if not terminal after MAX_WAIT: report projectId/jobId, stop, resume later with the same identifiers ``` Both runnable examples ([`examples/music/quickstart.py`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/music/quickstart.py), [`examples/music/quickstart.mjs`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/music/quickstart.mjs), [`examples/interpretation/quickstart.py`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/interpretation/quickstart.py), [`examples/interpretation/quickstart.mjs`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/interpretation/quickstart.mjs)) implement exactly this loop, including the `null` handling and the bounded wait. # Characters, quotes and billing Source: https://wiz-myvocal.mintlify.app/guides/characters-and-quotes How Speech to Text, Text-to-Music and Interpretation use Characters, reservations, settlement and release. Every product on this page is billed in **Characters** from your account balance. The rules differ by product, so start with the row for the product you integrate: | Product | How Characters are charged | Read | | - | - | - | | Speech to Text | Batch submission prices and reserves in one call; Real-time reserves while recording and settles confirmed audio at finish. There is no separate STT quote endpoint. | [Speech to Text billing](#speech-to-text-billing) | | Text to Music, Interpretation | Request a quote first; Characters are reserved when you accept it. | [Always quote, never estimate](#music-and-interpretation-always-quote-never-estimate) and the sections after it | | Text to Speech, Voice cloning, AI Cover | Not described on this page. Your plan, Character quotas and usage are returned by [Get account information](/api-reference/user/getInfo). | — | Rates are per plan. Never hard-code them; read the values the service returns, as described in each section. ## Speech to Text billing STT shares the workspace's Characters balance, STT rate card and History. Read [STT capabilities](/api-reference/stt/capabilities) for the account's Batch rate; use the returned session usage and final task billing for Real-time. Do not assume the two modes have the same rate. Batch submission prices and reserves the task in one call; there is no separate public STT quote endpoint. Real-time reserves capacity while recording and settles confirmed audio when finished. Unused reserved Characters are released. A `PARTIAL` result charges only the confirmed billable audio; use the returned billing values rather than the length you attempted to send. The duration-based calculation is `ceil(billableSeconds × ratePerMinute / 60)`. The service calculates this from the audio sample count. Optional processing features are included in the base rate, and multiple channels do not multiply the same file timeline's price. Equal-duration audio at different supported sample rates/encodings has the same charge at the same mode and rate. Read `billing.state`, `reservedCharacters`, `settledCharacters`, `releasedCharacters` and `billableCharacters` on the transcription. While reserved, `billableCharacters` can reflect the hold; it is not proof of final consumption. Monetary quantities here are Characters, not currency. Characters, sample counts and millisecond durations use decimal strings; bounded rates and indices are numbers. Reads, downloads, notification retries and repeated finish do not charge again. See [STT availability](/guides/stt-availability) for current validation and recovery limitations. The separate quote endpoints and product-specific rate tables below apply to Music and Interpretation. ## Music and Interpretation: always quote, never estimate Text-to-Music and Interpretation consume **Characters**. Nothing is charged by a read call: the cost is always quoted first, then reserved when you accept the quote. Quotes are free. This section and the rest of this page apply to Text-to-Music and Interpretation only. They do not change how Speech to Text prices and reserves at submission. Both products expose a `capabilities` endpoint and a `quotes` endpoint. Read the rate from `capabilities` and the exact amount from `quotes`. * `POST /sound_clone/api/v1/music/projects/{projectId}/quotes` * `POST /sound_clone/api/v1/interpretation/projects/{projectId}/quotes` Never hard-code a rate table into a client: rates are per plan, and the authoritative value for an account is what the service returns for that account. ## The formulas ### Text-to-Music ```text theme={null} quotedCharacters = ceil(durationSec × ratePerMinute / 60) ``` `durationSec` is the project's selected duration (`60`, `90`, `120` or `180`). The rate is the account's `ratePerMinute` from `capabilities`. ### Interpretation ```text theme={null} charactersPerTarget = ceil(durationMs × ratePerMinutePerLanguage / 60000) totalCharacters = charactersPerTarget × numberOfNewTargetLanguages ``` The rate is `account.charactersPerMinutePerLanguage` for the account's plan, and `durationMs` is the detected duration of the frozen source. Charging is **per new target language**: adding a language to an existing project only charges for the language being added, not for the ones that already exist. ## Plan rates These are the current plan rates published by the service. Always prefer the value returned for the specific account. **Text-to-Music — `ratePerMinute`** | Plan | Characters per minute | | - | - | | STANDARD | 2400 | | POPULAR | 2220 | | PRO | 1920 | | GROWTH | 1700 | | BUSINESS | 1440 | | ENTERPRISE | 1200 by default; an account-level contract override replaces it | **Interpretation — `charactersPerMinutePerLanguage`** | Plan | Characters per minute, per language | | - | - | | STANDARD | 4500 | | POPULAR | 4200 | | PRO | 4000 | | GROWTH | 3800 | | BUSINESS | 3600 | | ENTERPRISE | only a configured contract rate; otherwise quoting fails | | FREE | cannot generate | The two products do **not** share a fallback rule. Text-to-Music is fine with an ENTERPRISE account that has no explicit override and uses the plan default (1200). Interpretation is not: with an ENTERPRISE account and no configured contract rate, quoting fails with `code = 47119` instead of silently picking a number. Do not copy one product's fallback into the other. ## Worked examples **Text-to-Music, PRO plan, 90-second song** ```text theme={null} ceil(90 × 1920 / 60) = ceil(2880) = 2880 Characters ``` **Text-to-Music, POPULAR plan, 90-second song** ```text theme={null} ceil(90 × 2220 / 60) = ceil(3330) = 3330 Characters ``` **Interpretation, PRO plan, 90-second source, two new languages (Spanish and French)** ```text theme={null} ceil(90000 × 4000 / 60000) = ceil(6000) = 6000 Characters per language 6000 × 2 = 12000 Characters total ``` **Interpretation, same project, adding a third language later** ```text theme={null} 6000 × 1 = 6000 Characters (only the new language is charged) ``` ## Reading the numbers safely The API serializes 64-bit integers as **JSON strings** to avoid precision loss in JavaScript clients. Every Characters amount — `quotedCharacters`, `totalCharacters`, `perTargetCharacters`, `reservedCharacters`, `shortfall`, `remainingAfterGeneration`, `balances.*`, `targets[].characters` — arrives as a string such as `"12000"`. * Python: convert with `int(value)`. * Node.js: convert with `BigInt(value)` when the value can exceed `Number.MAX_SAFE_INTEGER` (`9007199254740993`); otherwise an explicit numeric parse is fine. Never `JSON.stringify` a value that is still a `BigInt`. * **Never** compare these values as strings. `"9000" < "10000"` is `false` lexicographically while `9000 < 10000` is `true` — string comparison gives the wrong answer. Request bodies are different: send numbers as JSON numbers (`durationSec: 90`, `size: 18432611`, `expectedVersion: 1`). Do not send strings just because responses use strings. ## The quote response A quote tells you the price and whether the account can afford it: | Field | Meaning | | - | - | | `quotedCharacters` / `perTargetCharacters` | the price | | `affordable` | whether the balance covers it | | `shortfall` | how much is missing (`"0"` when affordable) | | `remainingAfterGeneration` | the projected balance after the charge | | `balances.monthly` / `.additional` / `.total` | current balances by source | | `expiresAt` | when the quote stops being valid | | `state` | `ACTIVE`, `ALL_TARGETS_EXIST` or `CHANGED` | | `existingTargets` / `newTargets` | languages that already exist / would be created and charged | | `targets` | **the same content as `newTargets`**, kept under its pre-decision name — not a union with `existingTargets` | Music answers the same questions with `affordable`, `shortfall`, `remainingAfterGeneration` and `balances`, plus `ratePerMinute`, `rateVersion` and `quotedCharacters`. The balance fields are **per response and per product**, so do not apply one product's wording to the other: * Interpretation exposes `balanceState`, which is `AVAILABLE` or `LEDGER_UNAVAILABLE`, plus `availableCharacters` and `estimatedRemainingCharacters`. When the shared ledger read is unavailable, the two amounts are `null` and `balanceState` is `LEDGER_UNAVAILABLE` — a state, not a zero and not a guess. * Text-to-Music exposes `balances` (which may itself be `null` when the balance cannot be read) and has no `balanceState` field at all. * `account.accessState` is a different question again: for Interpretation it is one of `ENABLED`, `FREE_LOCKED`, `ENTERPRISE_UNRESOLVED`, `SYNCING` or `UNRESOLVED`; for Text-to-Music it is `ENABLED` or `DISABLED`. ## Quote lifetime and invalidation * A quote lives for `quoteTtlSeconds` — normally **600 seconds** (10 minutes). * Using an expired quote fails: Music `47006`, Interpretation `47108`. * Changing the inputs invalidates the quote. For Music that includes editing or regenerating the arrangement; an invalidated quote later fails with `47007`. When a quote expires, request a new one. Nothing has been charged. ## `ALL_TARGETS_EXIST` (Interpretation) If every requested language already exists for the frozen source, the quote returns: ```json theme={null} { "quoteId": null, "perTargetCharacters": null, "totalCharacters": "0", "state": "ALL_TARGETS_EXIST" } ``` This is a successful quote, not an error — and it is not something to pay for. Read `existingTargets` and use the targets that already exist. Never call the generation endpoint with a `null` `quoteId`. ## Reservation, settlement and release Charging is a three-phase lifecycle managed by the shared Characters ledger: 1. **Quote** — free. It only prices the work. 2. **Reserve** — when you accept the quote, the amount is *reserved* for that operation. In Music you receive `reservedCharacters` and one job; in Interpretation each target language gets its own reservation and its own `reservationCycle`. 3. **Settle or release** — after the real outcome, the reservation is *settled* (the Characters are consumed) or *released* (the Characters go back). Only the real ledger state may be described as settled or released. A job in `RECOVERY_REQUIRED` / `RECONCILING`, a failed HTTP response, a client timeout or an export in `RETRY` are **not** proof that a reservation was released, and none of them authorize telling a user that they were refunded. Query the resource and read its `billingState` / reservation state instead. Notes that follow from this model: * Each Interpretation target language settles or is released **independently**. One language may settle while another is released — that is the `PARTIAL_READY` case, and it is not a billing error. * Interpretation's `billingState` is `SETTLED`, `RESERVED`, `RELEASED` or `UNPRICED`, derived from the reservation and the target state. * A generation is settled at most once per target; retries run against the server's plan and never double-charge. ## Not enough Characters When the balance does not cover the quote: * `affordable` is `false` and `shortfall` tells you how much is missing. * Accepting the quote anyway fails with Music `47005` or Interpretation `47110`. Top up and re-quote. Do not split a single generation into smaller requests to work around the balance: the price is a property of the request, not of the remaining balance. ## Testing without spending real Characters There is no "test mode" endpoint. The examples in this repository are written so they can run against a **local deterministic stub server** that replies with the documented response shapes, which is how they are validated without consuming real Characters or calling a real provider. Point `MYVOCAL_API_BASE_URL` at your stub to do the same. Running the examples against the production host performs real, billable work and consumes Characters from the account that owns the API key. Use a stub for development, and check `affordable` and `shortfall` before accepting a real quote. # AI Cover quickstart Source: https://wiz-myvocal.mintlify.app/guides/cover-quickstart Submit a song and a Cover voice, receive the result on your callback URL, then fetch the cover from Cover History. AI Cover turns a song into a cover version sung by a chosen voice. It is asynchronous and uses **callbacks**: the request returns a `webhookId` immediately, and the result is posted to your `callbackUrl` when processing ends. ## Before you start * An API key; see [Authentication](/api-reference/authentication). * A public URL that accepts `POST` requests, to receive callbacks. Keep the same callback URL across related requests. See [Cover callbacks](/callback). * A voice for the cover: your custom voice's id or a premade voice's id. Use [List voices](/api-reference/voice/list) to find one. Creating your own Cover voice is optional; see [How to use voices](/guides/voice-quickstart#cover-voice). * The song file: mp3 or wav, up to 50 MB. ## Step 1: Generate the cover Send a `multipart/form-data` request to [Generate a cover](/api-reference/cover/cover): | Field | Required | Meaning | | - | - | - | | `voiceId` | Yes | Your custom voice's id or a premade voice's id. | | `title` | Yes | Up to 32 characters. If it is empty, the first 32 characters of the target song are used. | | `file` | Yes | The target song: mp3/wav, up to 50 MB. | | `callbackUrl` | Yes | Where the finished result is posted. | ```bash theme={null} curl --location --request POST 'https://api.myvocal.ai/sound_clone/api/v1/cover' \ --header 'accessKey: ' \ --form 'file=@"xxx/xxx.mp3"' \ --form 'voiceId="111"' \ --form 'title="test"' \ --form 'callbackUrl="http://www.google.com"' ``` The response returns a `webhookId`. Store it to match the callback: ```json theme={null} { "code": 1, "message": "Success", "data": { "webhookId": "7812" } } ``` ## Step 2: Receive the callback When the cover is finished, MyVocal sends a `POST` to your `callbackUrl` with `webhookType` `COVER_SONG`, the same `webhookId`, a `status` of `SUCCESS` or `FAILURE`, a `summary` and, on success, `data`. Match the callback to your request by `webhookId`. The payload is described in [Cover callbacks](/callback). ## Step 3: Get the cover audio from Cover History 1. List your covers to find the record id: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/cover/list' \ --header 'accessKey: ' ``` Page further back with `limit` (10 to 1000, default 10) and `startBeforeCoverId`. See [List Cover history](/api-reference/history/coverList). 2. Request playable URLs for up to 1,000 ids: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/cover/query' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "ids":["22","13"] }' ``` Each item in `data` has the record `id` and its audio `url`. See [Get Cover audio URLs](/api-reference/history/coverListUrl). To remove records, use [Delete Cover history](/api-reference/history/deleteCover) (up to 500 ids per request). ## Next steps Callback payload, statuses and samples. Create or improve your own Cover voice. # Make your first API request Source: https://wiz-myvocal.mintlify.app/guides/get-started Get your API key, verify it with a read-only account call, then choose the product you want to integrate. This page checks that your key works. It only reads your account information: it does not create a task, a voice or any other resource. No product requires you to complete the others first. ## Step 1: Get your API key Use a MyVocal account that has API access: 1. Sign in to [MyVocal Account](https://www.myvocal.ai/account). 2. Open Account Info. 3. Copy your API key. Every endpoint authenticates with the same header, `accessKey: `. Keep the key on your server. See [Authentication](/api-reference/authentication) for the details and security practices. ## Step 2: Verify the key Call [Get account information](/api-reference/user/getInfo). It is a read-only call. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/user/info' \ --header 'accessKey: ' ``` A valid key returns `code` `1` and your account data: ```json theme={null} { "code": 1, "message": "Success", "data": { "plan": "Business", "status": "active", "resetInDays": 2, "benefit": { "usedVoices": 146, "totalVoices": 150, "usedMonthlyChars": 3498604, "totalMonthlyChars": 3500000, "usedOrderChars": 0, "totalOrderChars": 0 } } } ``` Check `code`, not only the HTTP status: a failed request is also answered with HTTP `200` and a non-success `code` with a `message`. ## Step 3: Choose a product Each guide lists its own prerequisites. A cloned voice is needed only if you want to use your own voice in Text to Speech or AI Cover; Speech to Text, Text to Music and Interpretation never need one. Synthesize speech with a prebuilt or custom voice. Transcribe a recording (Batch quickstart). Create a custom voice for Text to Speech or AI Cover. Turn a song into a cover sung by a Cover voice. Generate an original song from a creative brief. Translate and dub uploaded audio/video. To transcribe live audio instead, start with the [Real-time quickstart](/guides/stt-realtime-quickstart). Looking for a specific endpoint? Open the [API directory](/api-reference/overview). # Interpretation quickstart Source: https://wiz-myvocal.mintlify.app/guides/interpretation-quickstart Translate and dub uploaded audio/video: upload a file, quote, generate, then play or export the dubbed versions. Interpretation takes an **uploaded audio or video file** and produces a translated, dubbed version of it, asynchronously. It is not live/interpreting in real time and it is not a microphone or WebSocket service: you upload a file, then poll until the result is ready. No cloned voice, workspace session or callback URL is required — only the `accessKey` header. Runnable clients for this guide: [`examples/interpretation/quickstart.py`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/interpretation/quickstart.py) and [`examples/interpretation/quickstart.mjs`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/interpretation/quickstart.mjs). Each one implements the whole flow below, including the multipart upload and the polling. ## Endpoint summary | Step | Method and path | | - | - | | 1 | `GET /sound_clone/api/v1/interpretation/capabilities` | | 2 | `POST /sound_clone/api/v1/interpretation/projects` | | 3 | `PATCH /sound_clone/api/v1/interpretation/projects/{projectId}/draft` | | 4 | `POST /sound_clone/api/v1/interpretation/projects/{projectId}/uploads` | | 5 | `POST /sound_clone/api/v1/interpretation/uploads/{uploadId}/parts` | | 6 | `PUT ` (object storage, not MyVocal) | | 7 | `POST /sound_clone/api/v1/interpretation/uploads/{uploadId}/complete` | | 8 | `GET /sound_clone/api/v1/interpretation/uploads/{uploadId}` | | 9 | `POST /sound_clone/api/v1/interpretation/projects/{projectId}/quotes` | | 10 | `POST /sound_clone/api/v1/interpretation/projects/{projectId}/generations` | | 11 | `GET /sound_clone/api/v1/interpretation/projects/{projectId}` | | 12 | `GET /sound_clone/api/v1/interpretation/assets/{assetId}/playback` | | 13 | `POST /sound_clone/api/v1/interpretation/targets/{targetId}/exports` | | 14 | `GET /sound_clone/api/v1/interpretation/exports/{exportId}/download` | ## What input is supported Read the accepted formats and limits from the service instead of hard-coding them: * `audioFormats` — accepted audio containers/extensions. * `videoFormats` — accepted video containers/extensions. * `exportFormats` — `mp3`, `wav`, `flac`, `mp4`. `mp4` is the composed video and only applies to a video source. * `maxSourceBytes` — the maximum declared upload size (a JSON **string**). * `languages[]` — the language entries you may request, each shaped `{ languageKey, displayName, sourceSupport }`. Send **`languageKey`** (for example `es`), not `displayName`. * `sourceSupport` — source-transcription evidence for that key, one of `CONFIRMED_ALIAS`, `CONFIRMED_NATIVE`, `REJECTED` or `UNVERIFIED`. It is separate from whether the key is a valid target language. * `languageCatalogState` — `CONFIGURED` when an authoritative list is configured. Share the same production limits note: the concrete production values are the ones the service returns at request time. Audio and video sources are both supported; a successful audio-source run does not by itself prove that every video container has been exercised end to end. ## Step 1: Read capabilities ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/capabilities' \ --header 'accessKey: ' ``` Look at `account.accessState`, `planRates`, `account.charactersPerMinutePerLanguage`, `quoteTtlSeconds` and the language/format lists. If `languageCatalogState` is `EMPTY`, quoting is not available for any language yet. `accessState` is `ENABLED` only when generation is allowed; `FREE_LOCKED`, `ENTERPRISE_UNRESOLVED`, `SYNCING` and `UNRESOLVED` each mean generation is not currently available, for different reasons. ## Step 2: Create the project ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 0d2b7c3a91f54b62' \ --data '{ "name": "Launch video ES/FR", "targetLanguages": ["es", "fr"] }' ``` ```json theme={null} { "code": 1, "message": "success", "data": { "projectId": "ip_...", "state": "DRAFT", "settingsVersion": 1, "requestId": "..." } } ``` `sourceLanguage` may be omitted, sent as `null`, as an empty string or as `AUTO` to auto-detect. `settingsVersion` is the concurrency anchor: draft and quote requests can carry the version they were based on, and a mismatch is rejected instead of silently overwriting someone else's change. ## Step 3: Set the draft (optional) ```bash theme={null} curl --location --request PATCH 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../draft' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "expectedVersion": 1, "sourceLanguage": "en", "targetLanguages": ["es", "fr"], "keyterms": ["MyVocal"], "cloningStrength": 7 }' ``` For PATCH, "field omitted or `null`" means **keep the current value**, while a provided array — including an empty one — **replaces** the whole list. `cloningStrength` is only defaulted to `7` when the stored draft has no value yet; it is not re-defaulted on every PATCH. ## Step 4: Create the upload session ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../uploads' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "filename": "launch.mp4", "size": 18432611, "contentType": "video/mp4" }' ``` ```json theme={null} { "code": 1, "message": "success", "data": { "uploadId": "iu_...", "projectId": "ip_...", "state": "CREATED", "declaredSize": "18432611", "partSizeBytes": 16777216, "totalParts": 2, "expiresAt": "2027-01-16T15:52:11" } } ``` * `filename` and `size` are required. `size` is the exact byte length of the file you will upload, and it must be greater than 0 and not greater than `maxSourceBytes` (read it from capabilities). * `contentType` is optional; when omitted or blank the service uses `application/octet-stream`. * `partSizeBytes` and `totalParts` come from the service. **Use both as returned**; do not assume a fixed 16 MiB chunk size. ## Step 5: Sign each part Ask for one presigned URL per part number, from `1` to `totalParts`: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/iu_.../parts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "partNumber": 1 }' ``` ```json theme={null} { "code": 1, "message": "success", "data": { "uploadId": "iu_...", "partNumber": 1, "method": "PUT", "url": "https:///...", "requiredHeaders": { "Content-Length": "16777216" }, "expiresAt": "2027-01-15T16:07:11" } } ``` ## Step 6: Upload the bytes Send the bytes for that part to the returned `url`, using the returned `method`, and include every header in `requiredHeaders`. The presigned `url` points at object storage, **not** at MyVocal. Do **not** send your `accessKey` (or any credential) to that URL — the signature in the URL is the authorization. Keep the `ETag` response header of every part: you need all of them in the next step. A part URL is short-lived (15 minutes by default). If you run out of time, request a fresh signed URL for the same part number — the session itself lasts 24 hours. ## Step 7: Complete the upload ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/iu_.../complete' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "parts": [ { "partNumber": 1, "etag": "" }, { "partNumber": 2, "etag": "" } ] }' ``` Send **all** parts in part-number order with the exact ETags returned by storage. A missing, extra or mismatched part list is rejected with `code = 47126`. After the object is assembled, the service probes the media and reads the real container, streams and duration. The response `state` may already be `READY`, or still be `COMPLETING`/`PROBING`; poll the next endpoint until it is `READY`. ## Step 8: Poll the upload until the source is ready ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/uploads/iu_...' \ --header 'accessKey: ' ``` Poll while `state` is `CREATED`, `UPLOADING`, `COMPLETING` or `PROBING`. When it is `READY`, `media` describes the detected input (`inputFormat`, `containerName`, `audioStreamCount`, `video`, dimensions) and `sourceVersion` is set. `COMPLETING` and `PROBING` do not mean you can generate yet. Only `READY` means the source is usable. A `FAILED` state carries an `errorCode`; `47125` means the file exceeded the size limit or had no content, `47127` means storage was unavailable. After a successful upload, `GET /projects/{projectId}` shows `source.state = FROZEN` with the detected `durationMs` and `media`. That frozen source version is what generation uses. ## Step 9: Quote the target languages ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../quotes' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "settingsVersion": 1, "targetLanguages": ["es", "fr"] }' ``` The cost formula is `ceil(durationMs × rate / 60000)` **per new target language**. The rate comes from your plan (`planRates` / `charactersPerMinutePerLanguage`). All Characters values (`perTargetCharacters`, `totalCharacters`, `availableCharacters`, `estimatedRemainingCharacters`, and every `targets[].characters`) are **JSON strings**. Convert them to integers before comparing or adding. Do not compare them lexicographically. Two important states: * `state = "ALL_TARGETS_EXIST"` means every requested language already exists for this source. Then `quoteId` is `null` and `totalCharacters` is `"0"`. Read `existingTargets` and do **not** call generation with a null `quoteId`. * Otherwise `state = "ACTIVE"` and `quoteId` is set. Quotes expire after `quoteTtlSeconds`. Adding a language later only charges for the **new** target languages. ## Step 10: Generate ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../generations' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 5ad0f3c7b21e4896' \ --data '{ "quoteId": "iq_..." }' ``` ```json theme={null} { "code": 1, "message": "success", "data": { "acceptanceId": "ia_...", "generationId": "ia_...", "projectId": "ip_...", "quoteId": "iq_...", "state": "ACCEPTED", "reservedCharacters": "6420", "reservationCycle": 1, "targets": [ { "targetId": "it_...", "language": "es", "jobId": "ij_...", "state": "QUEUED", "reservedCharacters": "3210" } ], "requestId": "..." } } ``` Idempotency here has two distinct behaviours, and neither is a byte-for-byte replay: * **Same key, same body**: the existing acceptance is returned; its target/job state may already have advanced. The stable anchors are `acceptanceId` and each `targetId`/`jobId`. * **Same quote, different key**: if that quote has already been accepted, the existing acceptance is returned again **without charging twice**, before any price re-check. This is intentional and differs from the Music rule. * **Same key, different body** (`code = 47111`): a real conflict. Do not silently switch to a new key; re-read the project to find out what already happened. ## Step 11: Poll each target Poll `GET /projects/{projectId}` until every `targets[].state` is `READY`, or until a target reaches `FAILED_RELEASED` (which is the only retryable state). Per-target progress is `QUEUED` → `PREPARING` → `TRANSLATING` → `EXPORTING` → `READY`. * `summaryState` rolls the project up: `DRAFT` (no targets), `PROCESSING`, `PARTIAL_READY`, `READY` (all targets ready) or `FAILED`. * `jobs[]` and `GET /jobs/{jobId}` give the per-job view. `RECONCILING` means the outcome is still being reconciled — it is **not** a failure and **not** a refund. Only a real ledger `RELEASED` state may be described as released. * `GET /jobs/{jobId}` returns `47117` when the job does not exist **or** does not belong to your account. The API never distinguishes the two. * `nextPollAfterMs` is currently `null` (the service does not publish a suggested interval yet). Use your own bounded interval, for example 2–5 seconds with jitter. ### Retrying a failed target Only a target with `action = "RETRY"` (state `FAILED_RELEASED`) may be retried: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/projects/ip_.../targets/it_.../retry-plan' \ --header 'accessKey: ' ``` The plan returns the server's `characters`, `rateVersion` and `nextReservationCycle`. Confirm them with `POST /targets/{targetId}/retry`; the amount fields are a confirmation of the server's plan, **not** client-side pricing. `OPERATION_RETRY` is replay-safe. ## Step 12: Play the result `GET /projects/{projectId}` gives each ready target an `outputAssetId`: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/assets/ia_.../playback' \ --header 'accessKey: ' ``` The response contains `state`, `mimeType`, a temporary `url`, `expiresAt` and `renewalAttemptLimit` (currently `1`: one renewal is allowed, then the authorization error must be surfaced). Request it when you need it; when it has expired, request a new one instead of caching it. ## Step 13: Export a file ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/targets/it_.../exports' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "format": "wav" }' ``` `format` must be one of `exportFormats` (`mp3`, `wav`, `flac`, `mp4`); `mp4` requires a video source. The response returns `exportId` and `state`. Export is asynchronous: `state` starts as `PROCESSING`, and `RETRY` is a transient retry of the same export. ## Step 14: Download the export ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/interpretation/exports/ie_.../download' \ --header 'accessKey: ' ``` Poll this **same** `exportId` while `state` is `PROCESSING` or `RETRY`; neither is a failure, and neither has a download URL yet. Do not create a new generation to work around it. When `state` is `READY`, `url` is the temporary product URL — download the bytes and, if the URL has expired, call this endpoint again for a fresh one. A non-empty `url` alone is not success: check that the returned `state` is `READY` and that the transfer actually produced media bytes. ## Managing projects * `GET /sound_clone/api/v1/interpretation/projects?page=1&pageSize=20` lists your projects (`pageSize` is `10`, `20` or `50`). * `PATCH /sound_clone/api/v1/interpretation/projects/{projectId}/name` renames a project. * `DELETE /sound_clone/api/v1/interpretation/projects/{projectId}` deletes it. * `DELETE /sound_clone/api/v1/interpretation/projects/{projectId}/source` removes the uploaded source and returns the project to a draft response. ## Billing in one sentence Quoting is free and charges nothing; generation reserves Characters per language, and each language settles or is released independently according to its real outcome. See [Characters, quotes and billing](/guides/characters-and-quotes). ## Next steps * [Interpretation API reference](/api-reference/interpretation/capabilities): every field, state and error. * [Async jobs, polling and retries](/guides/async-jobs-and-retries) and [Characters, quotes and billing](/guides/characters-and-quotes). # Text-to-Music quickstart Source: https://wiz-myvocal.mintlify.app/guides/music-quickstart Turn a creative brief into an original song and download the MP3 with the Text-to-Music API. Text-to-Music is asynchronous and **poll-based**. It does not need a cloned voice, a workspace session or a callback URL. Every request uses the `accessKey` header, and create/accept endpoints also require an `Idempotency-Key`. Runnable clients for this guide: [`examples/music/quickstart.py`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/music/quickstart.py) and [`examples/music/quickstart.mjs`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/music/quickstart.mjs). Each one implements the whole flow below, including the polling and the error handling. ## Endpoint summary | Step | Method and path | | - | - | | 1 | `GET /sound_clone/api/v1/music/capabilities` | | 2 | `POST /sound_clone/api/v1/music/projects` | | 3 | `GET /sound_clone/api/v1/music/projects/{projectId}` | | 4 | `GET /sound_clone/api/v1/music/jobs/{jobId}` | | 5 | `PUT /sound_clone/api/v1/music/projects/{projectId}/arrangement` | | 6 | `POST /sound_clone/api/v1/music/projects/{projectId}/arrangement/regenerate` | | 7 | `POST /sound_clone/api/v1/music/projects/{projectId}/quotes` | | 8 | `POST /sound_clone/api/v1/music/projects/{projectId}/generations` | | 9 | `GET /sound_clone/api/v1/music/projects/{projectId}/playback-url` | | 10 | `GET /sound_clone/api/v1/music/projects/{projectId}/download` | ## Step 1: Read capabilities `capabilities` tells you the account state, the rate card and the accepted enum values. Read the genre, mood, style, duration and vocal-language ranges from this response instead of hard-coding them. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/capabilities' \ --header 'accessKey: ' ``` Relevant fields: * `accessState` and `planKey`: whether this account may generate music. * `ratePerMinute`: the Characters rate for the account's plan. The charge is `ceil(durationSec × ratePerMinute / 60)`. * `supportedDurationsSec`: the durations you may request (`60`, `90`, `120`, `180`). * `supportedVocalLanguages`: an array of `{code, name}` entries. **Send the `code`** (for example `en`), not the display name. * `genres`, `moods`, `vocalStyles`, `lyricsModes`: the accepted enum values. * `quoteTtlSeconds`: how long a quote stays valid (`600`). ## Step 2: Create the project ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 6f1c1f0e0b8a4d1e' \ --data '{ "description": "An upbeat summer pop song about a road trip along the coast.", "genre": "POP", "styleNotes": "Bright synths, driving drums, warm bass.", "moods": ["UPLIFTING", "ENERGETIC"], "vocalLanguage": "en", "durationSec": 90, "lyricsMode": "AUTO", "vocalStyle": "BRIGHT_ENERGETIC" }' ``` A successful response returns the project and the arrangement job: ```json theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "projectStatus": "ARRANGEMENT_GENERATING", "job": { "jobId": "muj_...", "jobType": "ARRANGEMENT", "status": "QUEUED" }, "requestId": "..." } } ``` `Idempotency-Key` rules: * Must be unique per distinct operation, 16–64 printable ASCII characters. * The same key with the same body replays safely; the same key with a different body is rejected with `code = 47008`. * A replay does **not** return the first response byte-for-byte. Keep the `projectId`/`jobId` and re-query the resource instead. See [Async jobs, polling and retries](/guides/async-jobs-and-retries). ## Step 3: Poll until the arrangement is ready ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_...' \ --header 'accessKey: ' ``` Poll `GET /projects/{projectId}` (or the job with `GET /jobs/{jobId}`) until one of these is true: * `projectStatus` is `ARRANGEMENT_READY`: the arrangement is finished and you may quote. * the job's `terminal` field is `true`: stop. Inspect `lastFailure` (project) or `failure` (job). `ARRANGEMENT_READY` means **the arrangement is done — not that the song exists**. The finished song is only available when `projectStatus` is `READY` and `readyAsset` is present. ## Step 4: Review and optionally edit the arrangement `GET /projects/{projectId}` returns `arrangement` plus `arrangementVersion`. To change it: ```bash theme={null} curl --location --request PUT 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../arrangement' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "expectedVersion": 1, "title": "Coast Road", "styleSummary": "Bright summer pop with driving drums.", "tempoBpm": 118, "sections": [ { "sectionId": "", "lyrics": "...", "styleNotes": "..." } ] }' ``` You send only the fields that may change, addressed by `sectionId`. The service merges them into the immutable arrangement and re-validates the result. If `expectedVersion` no longer matches, the request is rejected with `code = 47016`; re-read the project and retry. To ask the service for a fresh arrangement instead: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../arrangement/regenerate' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 91b7c0de4a2f57c3' \ --data '{ "expectedVersion": 1 }' ``` Editing or regenerating the arrangement invalidates the current quote. ## Step 5: Quote before you spend Characters ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../quotes' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "arrangementVersion": 1 }' ``` The quote tells you exactly what the generation will cost: ```json theme={null} { "code": 1, "message": "success", "data": { "quoteId": "muq_...", "projectId": "mup_...", "arrangementVersion": 1, "durationSec": 90, "ratePerMinute": 2220, "quotedCharacters": "3330", "affordable": true, "shortfall": "0", "remainingAfterGeneration": "7170", "balances": { "monthly": "10500", "additional": "0", "total": "10500" }, "expiresAt": "2027-01-15T16:00:00" } } ``` Every Characters value in this response (`quotedCharacters`, `shortfall`, `remainingAfterGeneration`, `balances.*`) is a **JSON string**, because the API serializes 64-bit integers as strings to preserve precision. Convert it to a real integer before doing arithmetic or comparisons — never compare these values as strings. Quotes expire after `quoteTtlSeconds` (10 minutes); an expired quote is rejected with `code = 47006`. ## Step 6: Generate the song ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../generations' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --header 'Idempotency-Key: 3ce1a94f6d0b28e5' \ --data '{ "quoteId": "muq_..." }' ``` ```json theme={null} { "code": 1, "message": "success", "data": { "projectId": "mup_...", "jobId": "muj_...", "jobType": "SONG", "status": "QUEUED", "reservedCharacters": "3330", "createdAt": "2027-01-15T15:52:11" } } ``` `reservedCharacters` is a string for the same reason as above. Generation does not wait for the song; poll the job or the project. A quote can be consumed only once. Submitting the same `quoteId` again with a **different** idempotency key is rejected with `code = 47007`. To recover, keep the `projectId`/`jobId` and query the existing project instead of re-submitting. ## Step 7: Poll the song Poll `GET /projects/{projectId}` until `projectStatus` is `READY` and `readyAsset` is present, or until the job is terminal with a failure. Typical progress: | `projectStatus` | Meaning | | - | - | | `ARRANGEMENT_GENERATING` | The arrangement is still being generated | | `ARRANGEMENT_READY` | Arrangement finished; ready to quote | | `GENERATING` | The song and vocals are being created | | `READY` | The song exists; `readyAsset` is available | For jobs, `job.status` is `QUEUED`, `GENERATING`, `FINALIZING`, `SETTLING`, `READY`, `FAILED` or `RECOVERY_REQUIRED`, and `terminal` is `true` for `READY`, `FAILED` and `RELEASED`. `displayStage` gives a coarser, user-facing stage (`QUEUED`, `CREATING_MUSIC_AND_VOCALS`, `FINALIZING_LIBRARY_ITEM`, `RECOVERY_REQUIRED`). `RECOVERY_REQUIRED` is **not** a failure and not a refund. Keep the `projectId`/`jobId` and query them; do not submit a new paid generation. ## Step 8: Play and download ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../playback-url' \ --header 'accessKey: ' ``` Returns `{ "assetId": "...", "url": "...", "expiresAt": "..." }`. The playback URL is temporary (10 minutes), so request it when you need it rather than storing it. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/music/projects/mup_.../download' \ --header 'accessKey: ' \ --output song.mp3 ``` `GET /download` streams `audio/mpeg` bytes — it is **not** a JSON envelope on success. But when the request is rejected, the service answers with a JSON error envelope instead. Check the response `Content-Type` (or the `code` in the body) before saving the file, otherwise you may write an error message into a `.mp3`. ## Managing projects * `GET /sound_clone/api/v1/music/projects?page=1&pageSize=20` lists your projects. `page` must be ≥ 1 and `pageSize` must be `10`, `20` or `50`. * `PATCH /sound_clone/api/v1/music/projects/{projectId}/name` with `{ "name": "..." }` renames a project. * `DELETE /sound_clone/api/v1/music/projects/{projectId}` deletes it. If a generation is still in flight the request is rejected with `code = 47017` and the job is **not** cancelled. A successful delete is scoped to your ownership and is idempotent: success means the call needs no further delete handling — it is not proof that the project existed or that it was removed by this call. ## Billing in one sentence Quoting is free; generating reserves Characters at `ceil(durationSec × ratePerMinute / 60)`, and the shared ledger settles or releases the reservation according to the real outcome. Full detail is in [Characters, quotes and billing](/guides/characters-and-quotes). ## Next steps * [Music API reference](/api-reference/music/capabilities): every field, state and error. * [Async jobs, polling and retries](/guides/async-jobs-and-retries) and [Characters, quotes and billing](/guides/characters-and-quotes). # Speech to Text availability Source: https://wiz-myvocal.mintlify.app/guides/stt-availability Available STT workflows, current limitations and integration guidance. Batch and Real-time Speech to Text are available at `api.myvocal.ai` with your existing `accessKey`. Both use the workspace's STT rates, shared Characters balance and History. This page describes the release verified on October 5, 2026. ## Available workflows * **Batch:** multipart upload or a public `mediaUrl`, asynchronous submission and polling, optional bounded wait, transcript retrieval and deletion. * **Results and exports:** text, word/character alignment when requested, supported entity and text-processing options, per-channel results, and `txt`, `json`, `srt`, `segmented_json`, `html`, `docx` and `pdf` downloads. * **Real-time:** session creation, audio frames, partial/final results, manual or VAD commits, pause/resume within the tested session flow, explicit finish and one-use browser tickets. * **Billing:** optional processing features are included in the base STT rate. Multiple audio channels do not multiply the price of the same file timeline. Replaying a submission with the same idempotency key and unchanged input does not start another billable task. Read [capabilities](/api-reference/stt/capabilities) for account access, rates and current option constraints. An available mode does not mean every optional feature or option combination is supported. ## Parameter errors found by the model An `options.entityCategories` value that the model rejects is only detected when the task runs, so it ends as an asynchronous `FAILED` task with `error.errorCode = INPUT_INVALID` (earlier releases reported `MEDIA_UNREADABLE`). The audio is not at fault: review the requested categories instead of replacing the file. The failed transcription's reservation is released; check `billing` for the actual amounts. Do not retry an invalid parameter unchanged. A corrected request is a new logical task and needs a new `Idempotency-Key`. General schema errors and unsupported option combinations are still rejected as input errors. ## Completion notifications Completion delivery is implemented. Production verification of raw-body HMAC signatures, retries after a non-success response and receiver de-duplication is still incomplete. Keep polling as the authoritative result path. See the [notification contract](/guides/stt-batch-quickstart#completion-notifications) to implement and verify your receiver. Retries are bounded; delivery is not guaranteed. ## Real-time disconnections and recovery Explicit `finish`, reading the resulting History record, and repeated `finish` have been verified after a service replacement, including release of unconfirmed audio's reserved Characters. The complete disconnect → pause → resume into a new epoch flow across service replacement has not yet been verified. Do not assume uninterrupted recording or automatic recovery of missing audio. After a disconnect, read the session and its `accepting` state. Use the REST finish endpoint to close it when you are done; inspect `PARTIAL` results and usage. Never treat a closed socket as proof of successful transcription or final billing. ## Speaker matching and storage requests `matchKnownSpeakers` is not available. Speaker separation within a recording is a different feature and remains available through the documented options. `processingContentStorage` requests a processing-storage preference. Eligibility and the actual retention effect have not been verified. Acceptance of the request, or absence of a `PROCESSING_STORAGE_NOT_APPLIED` notice, is **not a zero-retention guarantee**. ## Client validation coverage Production real-time calls have been verified for all seven input encodings: PCM at 8, 16, 22.05, 24, 44.1 and 48 kHz and μ-law at 8 kHz, streamed from prepared audio files rather than from a real capture device. The browser example (a same-origin backend plus page) has been run in an isolated browser with a simulated microphone; real-microphone/device acceptance remains unverified. Always declare the actual sample rate and test your capture device. ## Next steps * [Batch quickstart](/guides/stt-batch-quickstart) and [Real-time quickstart](/guides/stt-realtime-quickstart). * [Speech to Text capabilities](/api-reference/stt/capabilities) for your account's rates and option constraints. # Speech to Text — Batch quickstart Source: https://wiz-myvocal.mintlify.app/guides/stt-batch-quickstart Upload a file, start a batch transcription, wait for the result and download it. Speech to Text turns an audio file into a transcript. The Batch API is asynchronous: you upload the file, submit a transcription, poll the task and download the result when it is `COMPLETED`. Batch and real-time results share the same History and the same Characters balance. Everything below uses the existing MyVocal API key. Start by reading [Authentication](/api-reference/authentication). See [availability and known limitations](/guides/stt-availability) before integrating optional notifications, speaker matching or processing-storage controls. ## 1. Read capabilities Confirms the account state, the rate for this account and the accepted enum values. ```bash theme={null} curl https://api.myvocal.ai/sound_clone/api/v1/stt/capabilities \ -H "accessKey: $MYVOCAL_ACCESS_KEY" ``` ## 2. Upload the audio Create an upload, send the parts, then complete it. The response gives you an `uploadId` for the next step. Presigned multi-part upload; the server probes the file and builds the canonical audio. ```bash theme={null} SIZE_BYTES=$(python -c 'import os; print(os.path.getsize("meeting.wav"))') UPLOAD=$(curl -s https://api.myvocal.ai/sound_clone/api/v1/stt/uploads \ -H "accessKey: $MYVOCAL_ACCESS_KEY" -H "Content-Type: application/json" \ -d '{"fileName":"meeting.wav","sizeBytes":'"$SIZE_BYTES"'}') UPLOAD_ID=$(echo "$UPLOAD" | python -c "import json,sys;print(json.load(sys.stdin)['data']['uploadId'])") ``` The request field is `sizeBytes` (the response reports the stored size separately). For each returned part, ask for a presigned URL and upload the bytes: ```bash theme={null} # partNumber starts at 1 and runs to totalParts curl -s https://api.myvocal.ai/sound_clone/api/v1/stt/uploads/$UPLOAD_ID/parts/1 \ -H "accessKey: $MYVOCAL_ACCESS_KEY" -X POST # PUT the returned part bytes, then complete: curl -s https://api.myvocal.ai/sound_clone/api/v1/stt/uploads/$UPLOAD_ID/complete \ -H "accessKey: $MYVOCAL_ACCESS_KEY" -H "Content-Type: application/json" \ -d '{"parts":[{"partNumber":1,"etag":""}]}' ``` Split the file using the returned `partSizeBytes`; PUT each part to its signed `url` and collect the object-storage response `ETag`. The snippets above show the request sequence; the [complete Python example](#complete-example) implements the byte splitting and PUT requests. See [Create an upload](/api-reference/stt/createUpload), [Sign a part](/api-reference/stt/signUploadPart) and [Complete an upload](/api-reference/stt/completeUpload) for the response fields. Submit only after the completed upload reports `READY`. ## 3. Submit the transcription Send the `uploadId` (or a public `mediaUrl` instead) with the options you want. Use an `Idempotency-Key` so a retry never pays twice: the same key and the same body return the same task. Quotes, reserves Characters and starts the task in one call. ```bash theme={null} # Generate once per logical task; reuse this value and the same body for retries. IDEMPOTENCY_KEY=$(python -c 'import uuid; print(uuid.uuid4())') curl https://api.myvocal.ai/sound_clone/api/v1/stt/transcriptions \ -H "accessKey: $MYVOCAL_ACCESS_KEY" -H "Content-Type: application/json" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -d '{"uploadId":"'"$UPLOAD_ID"'","languageHint":"en","options":{"separateSpeakers":true}}' ``` ## 4. Poll, then download Read the task, transcript and billing summary. Stop polling at `COMPLETED`, `PARTIAL` or `FAILED`; inspect the result or error instead of polling a failed task forever. `txt` (the default when `format` is omitted), `json`, `srt`, `segmented_json`, `html`, `docx` or `pdf`. Download is offered for `COMPLETED` tasks only; any other status returns `RESULT_NOT_READY`. A `PARTIAL` task (a real-time session that ended with some audio unconfirmed) is terminal and never becomes `COMPLETED`: read its confirmed text from the task view instead of downloading. ## Reading the result * **Language.** `languageHint` echoes what you asked for (`auto` when omitted); it is not a detection result. `detectedLanguage` and `transcript.languageCode` are filled only when the model returned a language, and use the model's three-letter code (for example `eng`); they are `null` otherwise. Real-time lines use two-letter codes (for example `en`). Compare languages with that difference in mind. * **Edited transcript.** With `rewriteInstruction`, `transcript.revisionStatus` is `APPLIED` (the edited text is in `transcript.revisedText`), `EMPTY` (the model returned no edited text), `FAILED` (with a MyVocal `revisionErrorCode`) or `NOT_REQUESTED`. The original `text`, the segments and the entity offsets always refer to the original transcript. * **Plain text.** `txt` puts a header line above each segment with its time range (when the segment is timed) and its speaker label, then the text, with a blank line between segments. Turn either part off with `exportOptions` (`includeTimestamps: false`, `includeSpeakers: false`). * **Subtitles.** SRT needs timing: segments without timestamps (for example with `alignmentLevel: none`) produce no cues, so an untimed result gives an empty SRT. Line wrapping with `maxCharactersPerLine` breaks at word boundaries; text without spaces, or a single word longer than the limit, is split between whole characters, so no text is lost and no character is cut. `maxSegmentChars` counts the separators MyVocal inserts when it rebuilds a segment. ## Options and export controls `options` controls Batch processing. A representative request: ```json theme={null} { "uploadId": "", "languageHint": "en", "title": "Weekly sync", "waitForCompletion": false, "options": { "separateSpeakers": true, "maxSpeakerCount": 4, "alignmentLevel": "word", "entityCategories": ["pii"], "removeDisfluencies": true, "vocabularyHints": ["MyVocal", "Kubernetes"], "separateChannels": false, "exportFormats": ["txt", "json", "srt"], "exportOptions": [ { "format": "srt", "maxCharactersPerLine": 42, "maxSegmentDurationS": 6 }, { "format": "json", "includeTimestamps": true, "includeSpeakers": true } ] } } ``` Read the [Batch option reference](/api-reference/stt/createTranscription#batch-options) and the live constraints in [capabilities](/api-reference/stt/capabilities). `exportFormats` only **pre-generates** those formats when the task completes; every format in `downloadFormats` stays downloadable either way. Each `exportOptions` entry applies its controls to one format, both to the pre-generated file and to later downloads of that format, and does not change another format. An unsupported combination is refused at submit with `INPUT_INVALID` rather than silently ignored. An entity category the model rejects ends the task as `FAILED` with `INPUT_INVALID` (not `MEDIA_UNREADABLE`); MyVocal does not keep its own category allowlist. ### Public media URLs With `mediaUrl`, MyVocal downloads the file itself, identifying as `MyVocal-STT-MediaFetcher/1.0 (+https://docs.myvocal.ai)`, and re-checks the public address of the real connection and of every redirect (at most 5). A failure carries `details.field = "mediaUrl"`, a `details.reason` and, when the host answered, `details.sourceStatus`: | `errorCode` | `details.reason` | Meaning | | - | - | - | | `INPUT_INVALID` | `DESTINATION_NOT_ALLOWED` | A private, loopback, link-local or metadata address; permanent | | `INPUT_INVALID` | `SOURCE_REFUSED` | The host answered but would not serve the file (for example 401/403/404) | | `INPUT_INVALID` | `TOO_MANY_REDIRECTS` | More than 5 redirects | | `INPUT_INVALID` | `UNSUPPORTED_TYPE` | The response is not a media type MyVocal accepts | | `TEMPORARILY_UNAVAILABLE` | `SOURCE_UNAVAILABLE` | The host returned 408, 429 or 5xx; retry later | | `TEMPORARILY_UNAVAILABLE` | `SOURCE_UNREACHABLE` | Name resolution or the connection failed; retry later | `MEDIA_UNREADABLE` means the file was downloaded but is not readable audio. ## Completion notifications Enable a signed completion callback inside the same `options` block. Notifications concern `COMPLETED` tasks; keep polling to detect failures and other terminal outcomes. Completion delivery is available, but production verification of raw-body signatures, retry delivery and receiver de-duplication is not yet complete. Use polling as your authoritative completion path and verify your receiver before relying on notifications. ```json theme={null} { "options": { "notifyOnCompletion": true, "notifyUrl": "https://customer.example/stt-callback", "clientMetadata": { "job": "weekly-sync" }, "notificationSigningSecret": "" } } ``` * A notification is sent when `notifyUrl` is present, unless `notifyOnCompletion` is `false`. `notifyOnCompletion: true` without `notifyUrl` is refused with `INPUT_INVALID`; it is never silently accepted. `notifyOnCompletion: false` with a `notifyUrl` sends nothing. * `notifyUrl` must be a public `http`/`https` URL; private, loopback, link-local and cloud-metadata addresses are refused on the real connection. * `notificationSigningSecret` is write-only: it is stored encrypted and never returned or logged. Changing the URL or the secret under the same `Idempotency-Key` is a different request. * MyVocal attempts delivery with bounded exponential backoff and a stable `eventId`. Delivery can fail after retries are exhausted; a receiver can also receive duplicates. Each signed delivery carries three MyVocal headers: | Header | Meaning | | - | - | | `X-MyVocal-Timestamp` | The signing timestamp. | | `X-MyVocal-Signature` | `v1=`. | | `X-MyVocal-Event-Id` | The stable event id, for de-duplication. | Read the timestamp from `X-MyVocal-Timestamp`, then compute the HMAC over the **concatenation of the timestamp, a `.` and the raw request body bytes**: ```python theme={null} import hashlib, hmac def verify(secret: bytes, timestamp: str, raw_body: bytes, header: str) -> bool: expected = hmac.new(secret, timestamp.encode() + b"." + raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest("v1=" + expected, header) ``` Verify against the **raw bytes exactly as received**; do not re-serialize the JSON, and do not sign the body without the timestamp prefix. Then de-duplicate by `X-MyVocal-Event-Id`. * **Polling is the authoritative result.** A missed or failed callback never changes the task; do not retry the transcription because a callback was missed. ## Complete example The runnable Batch client implements upload, submit, poll and download, then **deletes the test transcription**. It stops polling at `COMPLETED`, `PARTIAL` or `FAILED`; a `PARTIAL` task prints its readable text and status and stays in History. Running it again after completion creates a new billable task: [`examples/stt/stt_batch_minimal.py`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/stt/stt_batch_minimal.py). Read [Characters and quotes](/guides/characters-and-quotes) for how the charge and the shared balance work, and [Asynchronous jobs and retries](/guides/async-jobs-and-retries) for retry rules. ## Next steps * [Batch API reference](/api-reference/stt/createTranscription): every option, state and error. * [Real-time quickstart](/guides/stt-realtime-quickstart): transcribe live audio instead of files. * [Speech to Text billing](/guides/characters-and-quotes#speech-to-text-billing) and [availability](/guides/stt-availability). # Speech to Text — Real-time quickstart Source: https://wiz-myvocal.mintlify.app/guides/stt-realtime-quickstart Stream microphone or line audio to MyVocal and receive partial and final transcripts. The real-time API streams audio over a WebSocket and returns partial and final transcripts as they are produced. Like Batch, it uses the existing MyVocal API key, the same Characters balance and the same History. Read [availability and known limitations](/guides/stt-availability), especially the connection recovery and processing-storage notes. ## Choose how to connect | Option | Use it when | Where the API key lives | | - | - | - | | [Real-time SDK](/sdks/stt-realtime/overview) (Java, Go, Python) | Your server streams audio and you want framing, sample offsets, rotation and finish handled for you. | Your server | | Direct REST + WebSocket (this page) | Your server uses another language, or you want full control of the protocol. | Your server | | Browser with a server-issued ticket ([Step 3](#3-connect-the-socket)) | Audio is captured in a browser. Your server creates the session and a single-use ticket; the browser connects with `?ticket=`. | Your server only; never the browser | The steps below describe the direct protocol, which the SDKs implement for you. ## 1. Create a session Create a session with an `Idempotency-Key` and the options you want. The response returns a `sessionId`, a MyVocal `transcriptionId` and a `streamUrl`. Set the input encoding, the commit mode and the requested capabilities. ```bash theme={null} # Generate once for this session; reuse it and the same body for a retry. IDEMPOTENCY_KEY=$(python -c 'import uuid; print(uuid.uuid4())') SESSION=$(curl -s https://api.myvocal.ai/sound_clone/api/v1/stt/realtime/sessions \ -H "accessKey: $MYVOCAL_ACCESS_KEY" -H "Content-Type: application/json" \ -H "Idempotency-Key: $IDEMPOTENCY_KEY" \ -d '{"languageHint":"en","options":{"inputEncoding":"pcm_s16le_16000"}}') ``` ## 2. Send your audio with the right encoding `inputEncoding` must match the bytes you send. `pcm_s16le_16000` is signed 16-bit little-endian mono at 16 kHz; `mulaw_8000` is one μ-law byte per sample. Always declare the microphone's real sample rate, or a second of audio is interpreted as the wrong duration. Send audio as it is captured, in frames of about **100 ms**. Any frame size is accepted (there is no minimum frame length or frame rate), but each message has a fixed overhead, so merge very small pieces such as a browser's 128-sample `AudioWorklet` quanta. When you stream a file, pace frames by sample time (one second of audio per second) and keep the socket's local send buffer bounded instead of writing the whole file at once. `capturedSamples` counts everything captured so far, including audio not sent yet; `sampleOffset` counts the samples already sent in the current epoch. ## 3. Connect the socket A server client sends the `accessKey` header. A browser must not put its long-lived key in a URL: it uses a short-lived, single-use ticket and connects with `?ticket=`. In a customer-facing app, your backend keeps the API key and creates the session and ticket; send only the ticket and session information to the browser. The browser then connects straight to MyVocal's socket, so your backend needs no CORS opening and no general proxy: only fixed routes to create a session, issue a ticket, read a session and finish it, for sessions it created. The [browser example](#complete-examples) is a runnable version of that pattern. Issues a single-use browser ticket bound to the owner and the session. Send audio with a MyVocal event envelope and read the results: ```json theme={null} { "eventType": "audio.append", "epoch": 1, "payload": { "audioBase64": "...", "sampleOffset": 0, "capturedSamples": 16000 } } ``` The server answers with `session.ready`, `transcript.delta`, `transcript.final`, `transcript.alignment`, `transcript.revision`, `transcript.entities`, `usage.updated`, `session.notice`, `session.completed` and `session.error`, each with an `eventId`, `sessionId` and a monotonic `sequence`. ## 4. Pause, resume or commit * `segment.commit` submits the audio so far and **keeps** the session recording. * `session.pause` / `session.resume` close and reopen a recording segment (a new epoch). * `session.finish` flushes the tail, settles once and completes the task. `session.completed` arrives once the last final line and the supplements you requested are in, or at the cutoff of about 8 seconds after the last final line; a supplement still missing then is reported with a `SUPPLEMENT_NOT_RECEIVED` notice rather than waited for. See [Finish a session](/api-reference/stt/finishSession). The terminal call; a repeated finish returns the same task and never charges twice. ## 5. Events in detail Client to server, each as `{ "eventType", "epoch", "payload" }`: | `eventType` | `payload` | | - | - | | `audio.append` | `audioBase64` (the frame in the declared encoding), `sampleOffset` (samples already sent), `capturedSamples` (total captured), optional `precedingText` | | `segment.commit` | `capturedSamples` | | `session.pause` / `session.resume` | `capturedSamples` | | `session.finish` | `capturedSamples` | Server to client, each as `{ "eventId", "sessionId", "sequence", "eventType", "payload" }`: | `eventType` | `payload` | | - | - | | `session.ready` | the current session view (epoch, cursors, `accepting`) | | `transcript.delta` | `text` (temporary; replaces the previous delta) | | `transcript.final` | `id`, `text`, `revisedText`, `languageCode`, `languageProbability`, `entities`, `words`, `characterAlignments` | | `transcript.revision` | `id`, `text`, `revisedText` (the edited transcript arrived for that line) | | `transcript.entities` | `id`, `entities` (detected entities for that line; an empty list when its entities result arrived with none) | | `transcript.alignment` | `id`, `languageCode`, `languageProbability`, `words`, `characterAlignments` (late language/alignment) | | `usage.updated` | `estimatedCharacters`, `billableCharacters`, `elapsedMs`, `sentSamples`, `receivedSamples`, `capturedSamples` (all decimal strings), `accepting`, `epoch`, and `rotate`/`errorCode` when present | | `session.notice` | `code`, `message`; for example `PROCESSING_STORAGE_NOT_APPLIED`, or `SUPPLEMENT_NOT_RECEIVED` with `supplements` (`alignment`, `entities`, `revision`, `language`) and `lineIds` | | `session.completed` | the terminal session view | | `session.error` | `errorCode` (a MyVocal code) | All 64-bit quantities are decimal strings; `accepting`, `rotate` and `epoch` stay boolean/number. Each line's `languageCode` (two-letter, for example `en`) and `languageProbability` are that line's detection result when the model returned one; `languageHint` from the session is a request, not a detection. A frame that is not valid JSON, an unknown `eventType`, invalid base64 or a malformed `capturedSamples` is answered with `session.error` `INPUT_INVALID` and does not change the session. ## 6. Rotation, recovery and errors * A `usage.updated` with `rotate: true` and `accepting: false` means the server wants a new segment: call `session.pause`, then `session.resume` (a new `epoch`), and continue sending from the new epoch. The frame that received `rotate: true` was **not** stored: re-send every frame after the last acknowledged `sentSamples`, starting again at `sampleOffset` 0 in the new epoch. This applies to the last frame too: before `session.finish`, wait until `sentSamples` covers every captured sample and no rotation is pending. `session.ready` reports the live epoch and cursors so a reconnect knows where to resume. * A server `session.error` carries a MyVocal code (`INPUT_INVALID`, `PROVIDER_UNAVAILABLE`, `INSUFFICIENT_CHARACTERS`, `TEMPORARILY_UNAVAILABLE`, …). A plain disconnect is not a successful finish. Read the session over REST, then call [finish](/api-reference/stt/finishSession) to settle the audio the server can confirm. The result may be `PARTIAL`; unsent or unconfirmed audio is not restored by reconnecting. Full pause/resume across a service replacement is not yet verified. * A repeated frame at the same `sampleOffset`, a repeated `segment.commit` and a repeated `session.finish` are idempotent; they neither double-count nor create a second task. The production socket can disconnect after about 60 seconds without traffic. Server clients can send a WebSocket ping every 20 seconds while idle; browser clients should handle disconnects and read the session before deciding what to do next. `heartbeatIntervalMs` does not keep the client-to-MyVocal connection alive on its own. ## Complete examples * Node.js client using a one-use ticket, paced by sample time: [`examples/stt/stt_realtime_minimal.mjs`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/stt/stt_realtime_minimal.mjs) * Python server socket, paced by sample time: [`examples/stt/stt_realtime_minimal.py`](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/stt/stt_realtime_minimal.py) * Browser microphone: a same-origin Node.js backend that keeps the key plus the page, \~100 ms `AudioWorklet` frames, bounded stop/finish and close-out: [`examples/stt/browser/`](https://github.com/MyVocal-AI/API/tree/main/myvocal-api-docs/examples/stt/browser) (`node server.mjs`, see the [examples README](https://github.com/MyVocal-AI/API/blob/main/myvocal-api-docs/examples/stt/README.md)) Read [Characters and quotes](/guides/characters-and-quotes) for the billing rule. ## Next steps * [Real-time SDKs](/sdks/stt-realtime/overview) for Java, Go and Python. * [Real-time session reference](/api-reference/stt/createSession), [finish](/api-reference/stt/finishSession) and [browser tickets](/api-reference/stt/createTicket). * [Availability and known limitations](/guides/stt-availability). # How to use voices Source: https://wiz-myvocal.mintlify.app/guides/voice-quickstart Find a voice for Text to Speech or AI Cover, and optionally clone, improve, rename or delete your own. A voice is identified by a `voiceId`. Text to Speech and AI Cover take a `voiceId`; Speech to Text, Text to Music and Interpretation do not use voices at all. **Cloning is optional.** Start by listing the voices your API key can already use; create a custom voice only if you want your own. ## Two kinds of custom voices Custom voices are created for one feature. The `feature` field of [List voices](/api-reference/voice/list) shows which one. | | TTS voice | Cover voice | | - | - | - | | Used by | [Text to Speech](/quickstart) | [AI Cover](/guides/cover-quickstart) | | `feature` in the voice list | `text-to-speech` | `ai-cover` | | Create | [Create a TTS voice](/api-reference/voice/addTTSVoice) `POST /sound_clone/api/v1/voices/tts` | [Create a Cover voice](/api-reference/voice/addCoverVoice) `POST /sound_clone/api/v1/voices/vc` | | Result | `voiceId` returned in the response (`data.id`) | Training is asynchronous: a `webhookId` is returned, and the result is sent to your `callbackUrl` as `TRAIN_COVER_SPEAKER` ([Cover callbacks](/callback)) | | Improve | [Improve a TTS voice](/api-reference/voice/editTTSVoice) | [Improve a Cover voice](/api-reference/voice/editCoverVoice) (result sent as `EDIT_COVER_SPEAKER`) | | Audio files | mp3/wav/m4a, up to 10 MB each, up to 25 files | mp3/wav/m4a, up to 10 MB each, up to 25 files, more than 1 minute of effective voice in total (silence excluded) | The interactive playground on the create and improve pages cannot send file uploads. This is a limitation of the documentation playground, not of the API. Send the `multipart/form-data` requests from your own code or an HTTP tool, as in the examples below. ## Step 1: List the voices you can use ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices' \ --header 'accessKey: ' ``` Each item has an `id` (use it as `voiceId`), a `name`, a `type` (`cloned` or `designed`), a `feature` (`text-to-speech` or `ai-cover`) and a `channel` (`web` or `api`). * For the Accent TTS model, add `?modelId=myvocal_v3_accent_enhance`. That list includes your own compatible voices plus the prebuilt voices available to your API key. It is a selection aid, not a guarantee that a later generation will succeed. * [Generate a cover](/api-reference/cover/cover) accepts your custom voice's id or a premade voice's id. If a listed voice fits your use, you can go straight to [Text to Speech](/quickstart) or [AI Cover](/guides/cover-quickstart). ## Step 2: Create your own voice (optional) ### TTS voice ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices/tts' \ --header 'accessKey: ' \ --form 'files=@"xxx/xxx.mp3"' \ --form 'name="111"' ``` `name` must not exceed 32 characters. The response returns the new voice's id: ```json theme={null} { "code": 1, "message": "Success", "data": { "id": "7812" } } ``` Use `data.id` as `voiceId` in [Create speech](/api-reference/tts/tts). To improve the voice later, upload more files with [Improve a TTS voice](/api-reference/voice/editTTSVoice) (the 25-file limit includes the files you uploaded when creating it). ### Cover voice You need a public URL that accepts `POST` requests to receive the result; see [Cover callbacks](/callback). ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices/vc' \ --header 'accessKey: ' \ --form 'files=@"xxx/xxx.mp3"' \ --form 'name="111"' \ --form 'callbackUrl="http://www.google.com"' ``` The response returns a `webhookId` immediately: ```json theme={null} { "code": 1, "message": "Success", "data": { "webhookId": "1701406584rkzy91" } } ``` When training ends, MyVocal posts a `TRAIN_COVER_SPEAKER` callback with the same `webhookId` and a `status` of `SUCCESS` or `FAILURE`. The documented success sample carries the voice id in `data.id`. To improve a Cover voice, use [Improve a Cover voice](/api-reference/voice/editCoverVoice); its result arrives as an `EDIT_COVER_SPEAKER` callback. ## Step 3: Manage your voices | Task | Endpoint | | - | - | | Rename a voice | [Rename a voice](/api-reference/voice/updateVoiceName) `PUT /sound_clone/api/v1/voices/rename/{id}` | | Delete a custom voice | [Delete a voice](/api-reference/voice/delete) `DELETE /sound_clone/api/v1/voices/{id}` | Voice design is temporarily unavailable. Voices you created with it earlier are still returned by List voices and still work with Text to Speech; see [Voice Design (temporarily unavailable)](/api-reference/voice/designVoice). ## Next steps Synthesize speech with your `voiceId`. Create a cover with a Cover voice. # MyVocal API Source: https://wiz-myvocal.mintlify.app/introduction Choose a MyVocal product: Text to Speech, Speech to Text, Voice cloning, AI Cover, Text to Music or Interpretation. All MyVocal products share one public host, `https://api.myvocal.ai`, and one `accessKey` request header. Pick the product you need; each card starts at that product's shortest working path. You do not need to create a voice or try every product first. ## Choose a product **Input:** text and a `voiceId` (prebuilt or your own).
**Result:** an audio stream (normally `audio/mpeg`) in the response.
**Start:** TTS quickstart →
**Input:** an uploaded recording, a public media URL, or live audio.
**Result:** a transcript to poll and download (Batch), or partial and final events over a WebSocket (Real-time).
**Start:** Batch quickstart → (live audio: Real-time quickstart, below)
**Input:** your own mp3/wav/m4a recordings.
**Result:** a custom `voiceId` for Text to Speech or for AI Cover.
**Start:** How to use voices →
**Input:** a song file (mp3/wav) and a Cover voice.
**Result:** a cover version, reported to your callback URL and listed in Cover History.
**Start:** AI Cover quickstart →
**Input:** a creative brief (description, genre, moods, duration).
**Result:** an original song you poll for, then play or download as MP3.
**Start:** Text-to-Music quickstart →
**Translate and dub uploaded audio/video.**
**Input:** an uploaded audio or video file and target languages.
**Result:** translated, dubbed versions you poll for, then play or export.
**Start:** Interpretation quickstart →
Speech to Text has two starting points: the [Batch quickstart](/guides/stt-batch-quickstart) for recordings and the [Real-time quickstart](/guides/stt-realtime-quickstart) for live audio. ## Make your first request Get your key, verify it with one free read call, then pick a product. The `accessKey` header, where to find your key and how to keep it safe. Every endpoint, grouped by product. ## Real-time Speech to Text SDKs Server-side SDKs for the real-time Speech to Text API. They are optional: you can also call the REST and WebSocket API directly. Packages and runtimes. Python 3.10+ Java 8+ Go 1.22+ ## Voices and TTS models * Text to Speech and AI Cover take a `voiceId`. Cloning your own voice is optional; see [How to use voices](/guides/voice-quickstart). The other products do not use voices. - Text to Speech uses the default model path when you omit `modelId`, or the model you name with a public `modelId` such as `myvocal_v3`. See [TTS Models & Migration](/api-reference/tts/models) for the list. ## How results come back Products return results in different ways. Use the mechanism of the product you integrate: | Product | How you get the result | | - | - | | Text to Speech, Voice cloning (TTS voices), account information | In the HTTP response | | Speech to Text — Batch | Poll the transcription; an optional [signed completion notification](/guides/stt-batch-quickstart#completion-notifications) is available | | Speech to Text — Real-time | WebSocket events, then `finish` | | AI Cover, Cover voice creation and improvement | [Cover callbacks](/callback) to your `callbackUrl` | | Text to Music, Interpretation | Poll the project or job; see [Async jobs, polling and retries](/guides/async-jobs-and-retries) | For how Speech to Text, Text to Music and Interpretation charge Characters, see [Characters and billing](/guides/characters-and-quotes). Your plan and balance are returned by [Get account information](/api-reference/user/getInfo). # Text to Speech quickstart Source: https://wiz-myvocal.mintlify.app/quickstart Synthesize speech on the default TTS path, then optionally try myvocal_v3, the Accent model and TTS History. This quickstart uses production API host `https://api.myvocal.ai` and the `accessKey` request header. Steps 1–3 are the shortest path to one synthesized audio file. The optional sections after them are independent of each other; use only the ones you need. ## Step 1: Get your API key Use a MyVocal account with API access: sign in to [MyVocal Account](https://www.myvocal.ai/account), open Account Info and copy your API key. See [Authentication](/api-reference/authentication). ## Step 2: Get your user info and voices Use these calls first to confirm your key is valid and to get a usable `voiceId`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/user/info' \ --header 'accessKey: ' ``` ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices' \ --header 'accessKey: ' ``` Use an `id` from the voice list as `voiceId` in the next step. To use your own voice instead, create one first; see [How to use voices](/guides/voice-quickstart). ## Step 3: Create TTS with the default model path When `modelId` is omitted, the request uses the default model path. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "quickstart-default", "text": "Hello from MyVocal API quickstart.", "language": "en", "voiceSettings": { "stability": 0.7 } }' ``` The response body is the audio (normally `Content-Type: audio/mpeg`); add `--output output-default.mp3` to save it to a file. HTTP `200` alone does not mean success: if `Content-Type` is JSON, read `code` and `message`. See [Create speech](/api-reference/tts/tts) for all fields and errors. That is the whole shortest path. Everything below is optional. ## Optional branches | Branch | Use it when | | - | - | | [Request `myvocal_v3`](#optional-request-myvocal_v3-explicitly) | You want the V3 model instead of the default path. | | [Use the Accent model](#optional-use-the-accent-model) | You want `myvocal_v3_accent_enhance` with a compatible voice. | | [Query TTS History](#optional-query-tts-history-and-output-urls) | You need earlier records or playable URLs for them. | ## Optional: request `myvocal_v3` explicitly Set `modelId` to `myvocal_v3` to explicitly request V3. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "quickstart-v3", "text": "Hello from MyVocal V3 model path.", "language": "en", "modelId": "myvocal_v3", "voiceSettings": { "stability": 0.5 } }' ``` `myvocal_v3` is publicly documented. If your request returns `code = -1`, verify `voiceId`, `language`, account plan, and current backend availability before retrying. ## Optional: use the Accent model ### Discover Accent-compatible voices An Accent request must use a voice that is compatible with the Accent model. Ask for that list explicitly and pick a returned `id` as the `voiceId` for the next step. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/voices?modelId=myvocal_v3_accent_enhance' \ --header 'accessKey: ' ``` The list includes your own compatible voices plus the prebuilt voices available to your API key. It is a selection aid: a voice appearing in it is not a guarantee that a later generation will succeed. ### Create TTS with the Accent model Send the same request shape as the default path, with `modelId` set to `myvocal_v3_accent_enhance`. Use `--output` to save the returned audio to a file: ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "voiceId": "", "title": "quickstart-accent", "text": "Hello from the MyVocal Accent model.", "modelId": "myvocal_v3_accent_enhance" }' \ --output output-accent.mp3 ``` * `language`: omit it, or send `auto`, to let the model detect the language. The Accent model accepts its own list of 40 language codes plus `auto`; see [TTS Models & Migration](/api-reference/tts/models). A plain V3 code the Accent model does not support (for example `hmn`) is rejected with `code = 10004`. * `voiceSettings.stability`: a value inside the legal range (`0.1` to `1`) is accepted for compatibility but has no effect on this model. An out-of-range value is rejected with `code = 10006`. * Streaming: `POST /sound_clone/api/v1/tts/stream` takes the same body. Read `Content-Type` before trusting the body. On success the body is audio (`Content-Type: audio/mpeg`). When the request is rejected, or generation fails before any audio is sent, the service answers with HTTP `200` and a JSON envelope whose `code` is not a success code. **HTTP `200` alone does not mean the request succeeded.** If the connection is interrupted after audio has already started, the transfer simply ends rather than appending JSON, so treat a short file as a failed request. ## Optional: query TTS History and output URLs 1. Query TTS list to get generated record IDs. 2. Query URL endpoint with those IDs to get playable output URLs. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/list?limit=10' \ --header 'accessKey: ' ``` `GET /sound_clone/api/v1/tts/list` is a GET endpoint with two optional query parameters: * `limit`: `10` to `1000`, default `10`. A value outside that range is rejected with `code = 10027`. * `startBeforeTTSId`: cursor for older history. The row with that id is **included** in the page (`id <= startBeforeTTSId`), so pass the id of the oldest row you already have to continue further back. An id you cannot see is rejected with `code = 10019`. The response contains `list`, `hasMore` and `earliestHistoryItemId`. ```bash theme={null} curl --location 'https://api.myvocal.ai/sound_clone/api/v1/tts/query' \ --header 'accessKey: ' \ --header 'Content-Type: application/json' \ --data '{ "ids": [""] }' ``` See [TTS History](/api-reference/history/ttsList) for the full reference. Open TTS Models & Migration for the current public model list and migration guidance. ## Other products These are separate products with their own quickstarts; they are not steps of this TTS quickstart. Speech to Text, Text to Music and Interpretation do not need a `voiceId`. AI Cover does: [Generate a cover](/api-reference/cover/cover) requires the `voiceId` of a compatible Cover voice (your custom voice's id or a premade voice's id). See [How to use voices](/guides/voice-quickstart) to find or create one. Stream live audio and receive partial and final transcripts. Transcribe a recording (Batch quickstart). Brief → arrangement → quote → generate → MP3. Translate and dub uploaded audio/video: upload → probe → quote → generate → export. Turn a song into a cover sung by a Cover voice. # Real-time SDKs — behaviour guide Source: https://wiz-myvocal.mintlify.app/sdks/stt-realtime/behavior How the Java, Go and Python real-time SDKs frame audio, end sessions, handle disconnects and report results. The three SDKs behave the same way; only the naming follows each language. ## The normal path 1. Create one client per application with your access key. 2. `connect` with a session request (`title`, `languageHint`, `options`). Register event handlers here, before any event can arrive. 3. Send audio: a file (`sendFile`, paced by sample time), a stream, or byte chunks of any size (`sendAudio`). The SDK builds frames of about 100 ms and joins half PCM samples across calls. A live source that already arrives at capture speed is not paced again. 4. Optional: `commit` closes the current line and keeps recording; `pause` and `resume` start a new epoch. 5. `finish` sends the remaining audio, waits until every sample is acknowledged, ends the session and returns the result: `status` (`COMPLETED`, `PARTIAL` or `FAILED`, exactly as the service reports it), `transcriptionId`, `usage`, `notices` and the lines. 6. `close` releases all local resources. ## finish and close are different | | `finish` | `close` | | - | - | - | | Ends the session | Yes. Repeated calls return the same result | No. An unfinished session is paused when its connection goes away | | Settles Characters | Yes, by the service | No | | Returns the result | Yes | No | | Releases local resources | Closes the session's connection only | Yes, completely: connection, threads and tasks, event queues; the client stops holding the session | Call `finish`, then `close` (for example in a `finally` block). Every wait has a configurable timeout, so this never hangs. ## Acknowledgements are not billing `usage.updated` reports transport receipt (`sentSamples`, `receivedSamples`). The amount charged is the service's `billableCharacters` in the final result and in History. The SDKs never compute prices. ## Empty results and missing results * Entities `null` / `None` / `nil`: the entities result has not arrived. * An empty list with `entitiesArrived = true`: it arrived and is empty. This is a valid result. * A supplement that never arrives is reported as a `SUPPLEMENT_NOT_RECEIVED` notice naming the line and the kind. The SDKs never guess from silence, and never change a `COMPLETED` session to `FAILED` because a supplement is missing. ## Disconnects and timeouts The SDKs do not reconnect or resend audio after a network failure. When the connection drops, when acknowledgements stop while audio is outstanding, or when the completion event does not arrive in time, the SDK: 1. stops accepting audio (further input raises a connection-lost error); 2. reads the original session over REST and returns it if it has already ended; 3. otherwise finishes it over REST (idempotent) within the close-out timeout. That timeout is one budget for the whole close-out: every REST read, finish and retry wait gets only the time that is left, and nothing new starts once it is used up; 4. returns the real result, marked `viaRest` with a `closeoutReason` (`DISCONNECTED`, `ACK_TIMEOUT`, `FINISH_TIMEOUT`). If REST cannot be reached, you get a *finish unconfirmed* error with the `sessionId`. Call `getSession` or `finishSession` later. Audio the service never acknowledged is not treated as received, and no new session is created. Recovery across processes or servers is not provided. ## Pause and resume `pause` sends and confirms buffered audio, then closes the current epoch. Sending audio while paused is a state error, so the paused time is never sent as audio. `resume` opens a new epoch: `sampleOffset` starts again at 0 and `capturedSamples` keeps counting. Both work over the WebSocket or REST. ## Buffering, callbacks and concurrency * The SDK holds at most 30 seconds (configurable) of audio that has not been acknowledged yet. When it is full, `sendAudio` waits; without acknowledgement progress it raises a back-pressure error. Audio is never dropped silently. `sendFile` reads the file frame by frame as the buffer has room, so memory does not grow with the file size. * Handlers and event iteration run off the network path and use bounded queues (configurable size), so a slow consumer never delays acknowledgements. Handler errors go to the callback-error hook and are counted; they are never reported as service failures. If a queue overflows, no event is dropped silently: each undelivered event is counted and reported to the callback-error hook, and the final result still has every line. * Operations on one session run one at a time. Different sessions are independent. ## Observed service behaviour These were seen in real-API testing; the root cause is not confirmed. The SDKs report them exactly as the service returns them. Read `status`, `notices` and `usage` of the result; the service's final state is authoritative. * **Long idle.** After an audio gap of about 75 seconds or more, the service may stop acknowledging further audio. The SDK then closes the session out after the acknowledgement timeout, and the session may end `PARTIAL`. The WebSocket ping keeps the connection open, but it does not guarantee that the session keeps processing audio. * **Manual segment mode.** In manual mode the service may return `PARTIAL` even when all audio was received (the receipt counters show every sample). Manual mode remains supported. ## Blocking and asynchronous calls | Language | Blocking | Asynchronous | | - | - | - | | Java | `connect`, `finish` | `connectAsync`, `finishAsync` (`CompletableFuture`; `cancel(true)` interrupts the wait), `RealtimeListener` | | Go | every call takes a `context.Context`; cancel it to stop waiting | handlers, `OnEvent` or `EventChannel` | | Python | `RealtimeClient` | `AsyncRealtimeClient` (`await`), handlers or event iteration | ## Network and security * The access key travels only in the `accessKey` header, never in a URL. * TLS verification is always on. You can add a private CA and set an explicit proxy. An HTTP client you pass in is never closed by the SDK. * The client sends a WebSocket ping every 20 seconds to keep idle connections open. Pings are not audio and are unrelated to the `heartbeatIntervalMs` option. * The SDKs never log audio, transcript text, keys, tickets or authentication headers. ## Timeouts Defaults: request 30 s, create 30 s (with idempotent retries), connect 15 s, acknowledgement 10 s (counted only while audio is unacknowledged), finish 60 s, close-out 70 s, close 5 s. These are client settings, not service latency guarantees. ## Audio input Encodings: `pcm_s16le_8000`, `pcm_s16le_16000`, `pcm_s16le_22050`, `pcm_s16le_24000`, `pcm_s16le_44100`, `pcm_s16le_48000` (signed 16-bit little-endian mono) and `mulaw_8000`. The SDKs read WAV headers and reject a WAV whose format differs from the session encoding. Convert MP3, URLs or microphone input outside the SDK, for example with FFmpeg; the packages have no FFmpeg or sound-card dependency. # Real-time SDK — Go Source: https://wiz-myvocal.mintlify.app/sdks/stt-realtime/go Stream audio to MyVocal Speech to Text from Go 1.22+ with package sttrealtime. ```bash theme={null} go get github.com/MyVocal-AI/myvocal-stt-realtime-sdks/go@v1.0.0 ``` Go 1.22 or later. Dependency: `github.com/gorilla/websocket`. Served by the Go module proxy from the `go/v1.0.0` tag of [MyVocal-AI/myvocal-stt-realtime-sdks](https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks). ## Stream a file ```go theme={null} import sttrealtime "github.com/MyVocal-AI/myvocal-stt-realtime-sdks/go" client, err := sttrealtime.NewClient(sttrealtime.Config{AccessKey: os.Getenv("MYVOCAL_ACCESS_KEY")}) if err != nil { log.Fatal(err) } defer client.Close() ctx := context.Background() session, err := client.Connect(ctx, sttrealtime.ConnectOptions{ Request: &sttrealtime.SessionRequest{Title: "meeting", LanguageHint: "en", Options: &sttrealtime.SessionOptions{InputEncoding: "pcm_s16le_16000", SegmentCommitMode: "vad"}}, Handlers: map[string]func(sttrealtime.Event){ sttrealtime.EventTranscriptFinal: func(e sttrealtime.Event) { fmt.Println("final:", e.Text()) }, }, }) if err != nil { log.Fatal(err) } defer session.Close() // local resources only if err := session.SendFile(ctx, "speech.wav", true); err != nil { log.Fatal(err) } // paced result, err := session.Finish(ctx) if err != nil { log.Fatal(err) } fmt.Println(result.Status, result.TranscriptionID) ``` Every call takes a `context.Context`; cancel it to stop waiting. Optional booleans and numbers use `sttrealtime.Bool`, `Int` and `Float`, so `false` and `0` are sent as given and `nil` is omitted. ## Byte chunks and events ```go theme={null} session, err := client.Connect(ctx, sttrealtime.ConnectOptions{Request: req, EventChannel: true, OnCallbackError: func(err error, e sttrealtime.Event) { log.Println("handler failed on", e.Type) }}) go func() { for e := range session.Events() { /* typed: e.Type, e.Text(), e.Usage(), e.Notice() ... */ } }() for chunk := range captured { // any size; not paced again if err := session.SendAudio(ctx, chunk); err != nil { break } } result, err := session.Finish(ctx) ``` ## Commit, pause and resume ```go theme={null} err = session.Commit(ctx) // line boundary; same epoch err = session.Pause(ctx, sttrealtime.ViaWS) // or ViaREST err = session.Resume(ctx, sttrealtime.ViaREST) // new epoch ``` ## After a disconnect ```go theme={null} result, err := session.Finish(ctx) var unconfirmed *sttrealtime.FinishUnconfirmedError switch { case err == nil && result.ViaREST: log.Println("closed out:", result.Status, result.CloseoutReason) case errors.As(err, &unconfirmed): view, gerr := client.GetSession(ctx, unconfirmed.SessionID) // later if gerr == nil && !view.IsTerminal() { view, gerr = client.FinishSession(ctx, unconfirmed.SessionID, nil) } } ``` ## Config | Field | Default | Meaning | | - | - | - | | `BaseURL` | `https://api.myvocal.ai` | `http`/`https`; the stream uses `ws`/`wss` | | `Timeouts` | see [behaviour guide](/sdks/stt-realtime/behavior#timeouts) | zero fields use defaults | | `FrameMs`, `MaxBufferedMs` | 100, 30000 | frame size and the bound of unacknowledged audio | | `PingInterval` | 20 s | client WebSocket ping | | `EventQueueSize` | 10000 | bound of events waiting for handlers | | `HTTPClient`, `Proxy` (`NoProxy`, `ProxyURL`), `TLSConfig` | environment proxy, system roots | a borrowed client is never closed | | `DisableCloseoutOnDisconnect` | `false` | turn off the automatic REST close-out after an unexpected disconnect (`Finish` still closes out) | ## Errors Use `errors.Is` with `ErrInputInvalid`, `ErrAuthentication`, `ErrInsufficientCharacters`, `ErrNotFound`, `ErrIdempotencyConflict`, and `errors.As` with `*APIError` (`Code`, `ErrorCode`, `Retryable`, `RequestID`), `*AudioFormatError`, `*SessionStateError`, `*ConnectionLostError`, `*BackpressureTimeoutError`, `*FinishUnconfirmedError` (`SessionID`) and `*TransportError`. # Real-time SDK — Java Source: https://wiz-myvocal.mintlify.app/sdks/stt-realtime/java Stream audio to MyVocal Speech to Text from Java 8+ with ai.myvocal:myvocal-stt-realtime. `ai.myvocal:myvocal-stt-realtime:1.0.0` is distributed as files on the [GitHub Release](https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/tag/v1.0.0). Install them into your local Maven repository: ```bash theme={null} base=https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/download/v1.0.0 for f in myvocal-stt-realtime-1.0.0.jar myvocal-stt-realtime-1.0.0-sources.jar \ myvocal-stt-realtime-1.0.0-javadoc.jar myvocal-stt-realtime-1.0.0.pom SHA256SUMS; do curl -fsSLO "$base/$f" done sha256sum --check --ignore-missing SHA256SUMS mvn install:install-file -Dfile=myvocal-stt-realtime-1.0.0.jar -DpomFile=myvocal-stt-realtime-1.0.0.pom \ -Dsources=myvocal-stt-realtime-1.0.0-sources.jar -Djavadoc=myvocal-stt-realtime-1.0.0-javadoc.jar ``` Then add the dependency: ```xml theme={null} ai.myvocal myvocal-stt-realtime 1.0.0 ``` Java 8 or later; no Spring. The only runtime dependency is OkHttp 5 (with Okio and the Kotlin standard library, all Java 8 compatible). ## Stream a file (blocking) ```java theme={null} import ai.myvocal.stt.realtime.*; import java.nio.file.Paths; try (RealtimeClient client = RealtimeClient.builder(System.getenv("MYVOCAL_ACCESS_KEY")).build()) { SessionRequest request = new SessionRequest().title("meeting").languageHint("en") .options(new SessionOptions().inputEncoding("pcm_s16le_16000").segmentCommitMode("vad")); RealtimeSession session = client.connect(new ConnectOptions().request(request) .on(RealtimeEvent.TRANSCRIPT_DELTA, e -> System.out.println(" ... " + e.getText())) .on(RealtimeEvent.TRANSCRIPT_FINAL, e -> System.out.println("final: " + e.getText()))); try { session.sendFile(Paths.get("speech.wav"), true); // WAV header checked; paced by sample time FinishResult result = session.finish(); System.out.println(result.getStatus() + " " + result.getTranscriptionId() + " " + result.getUsage().getBillableCharacters()); } finally { session.close(); // local resources only } } ``` ## Byte chunks with CompletableFuture and a listener ```java theme={null} RealtimeSession session = client.connectAsync(new ConnectOptions().request(request) .listener(new RealtimeListener() { @Override public void onTranscriptFinal(TranscriptLine line, RealtimeEvent event) { ... } @Override public void onNotice(Notice notice) { ... } }) .onCallbackError((error, event) -> log.warn("handler failed on {}", event.getType()))) .get(30, TimeUnit.SECONDS); byte[] chunk = new byte[1234]; // any size int n; while ((n = in.read(chunk)) > 0) { session.sendAudio(chunk, 0, n, null); // waits only when the buffer is full } FinishResult result = session.finishAsync().get(120, TimeUnit.SECONDS); session.close(); ``` ## Commit, pause and resume ```java theme={null} session.commit(); // line boundary; keep sending in the same epoch session.pause(); // or pause(RealtimeSession.Via.REST) session.resume(RealtimeSession.Via.WS); // new epoch; sampleOffset restarts at 0 ``` ## After a disconnect ```java theme={null} try { FinishResult result = session.finish(); // REST close-out of the same session if needed if (result.isViaRest()) { log.info("closed out: {} ({})", result.getStatus(), result.getCloseoutReason()); } } catch (FinishUnconfirmedException e) { String id = e.getSessionId(); // keep it; later: SessionView view = client.getSession(id); if (!view.isTerminal()) { view = client.finishSession(id, null); } } ``` ## Client options | Builder method | Default | Meaning | | - | - | - | | `baseUrl` | `https://api.myvocal.ai` | `http`/`https`; the stream uses `ws`/`wss` | | `timeouts(new Timeouts().withAckMillis(...))` | see [behaviour guide](/sdks/stt-realtime/behavior#timeouts) | all waits are bounded | | `frameMs`, `maxBufferedMs` | 100, 30000 | frame size and the bound of unacknowledged audio | | `pingIntervalMillis` | 20000 | client WebSocket ping | | `eventQueueSize` | 10000 | bound of events waiting for handlers | | `proxy(Proxy)`, `sslSocketFactory(factory, trustManager)`, `httpClient(OkHttpClient)` | JVM defaults | network; a borrowed client is never shut down | | `closeoutOnDisconnect` | `true` | REST close-out after an unexpected disconnect | ## Errors | Exception | When | | - | - | | `InputInvalidException` | invalid option or combination (not retried) | | `AuthenticationException` | invalid key (not retried) | | `InsufficientCharactersException` | balance exhausted (not retried) | | `ApiException` | other `code != 1` envelopes (`getErrorCode()`, `isRetryable()`, `getRequestId()`) | | `AudioFormatException` | format mismatch, or half a sample left at `finish` (`discardPartialSample()`) | | `SessionStateException` | e.g. audio while paused | | `ConnectionLostException` | audio after the connection was lost | | `FinishUnconfirmedException` | the end could not be confirmed; carries `getSessionId()` | | `CancellationException` | the calling thread was interrupted | # Real-time SDKs — install Source: https://wiz-myvocal.mintlify.app/sdks/stt-realtime/overview Install the server-side Java, Go and Python SDKs for the MyVocal Speech to Text real-time API. Server-side SDKs for the [Speech to Text real-time API](/guides/stt-realtime-quickstart). They are optional: any language can call the REST and WebSocket API directly. They use the same API key, Characters balance and History as the REST API. | Language | Package | Runtime | | - | - | - | | Java | `ai.myvocal:myvocal-stt-realtime:1.0.0` | Java 8 or later (verified on 8, 11, 13, 17, 21); no Spring | | Go | `github.com/MyVocal-AI/myvocal-stt-realtime-sdks/go` `v1.0.0`, package `sttrealtime` | Go 1.22 or later | | Python | `myvocal-stt-realtime` `1.0.0` (blocking and `asyncio` clients) | Python 3.10 or later | Use the SDKs on your server only. The access key must never reach a browser or mobile app. For a browser client, call `createTicket` on your server and pass the single-use ticket to the browser. The SDKs themselves always connect with the access key. ## Install Install 1.0.0 with the command for your language. Go is served by the Go module proxy (tag `go/v1.0.0`). Python (wheel and sdist) and Java (JAR, sources, Javadoc and POM) are distributed as files on the [GitHub Release v1.0.0](https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/tag/v1.0.0), together with release notes and `SHA256SUMS`. Source code: [MyVocal-AI/myvocal-stt-realtime-sdks](https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks) (Apache License 2.0). ```bash Go theme={null} go get github.com/MyVocal-AI/myvocal-stt-realtime-sdks/go@v1.0.0 ``` ```bash Python theme={null} pip install https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/download/v1.0.0/myvocal_stt_realtime-1.0.0-py3-none-any.whl ``` ```bash Java theme={null} base=https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/download/v1.0.0 for f in myvocal-stt-realtime-1.0.0.jar myvocal-stt-realtime-1.0.0-sources.jar \ myvocal-stt-realtime-1.0.0-javadoc.jar myvocal-stt-realtime-1.0.0.pom SHA256SUMS; do curl -fsSLO "$base/$f" done sha256sum --check --ignore-missing SHA256SUMS mvn install:install-file -Dfile=myvocal-stt-realtime-1.0.0.jar -DpomFile=myvocal-stt-realtime-1.0.0.pom \ -Dsources=myvocal-stt-realtime-1.0.0-sources.jar -Djavadoc=myvocal-stt-realtime-1.0.0-javadoc.jar ``` For Java, after installing the files into your local Maven repository, add the dependency: ```xml theme={null} ai.myvocal myvocal-stt-realtime 1.0.0 ``` Set `MYVOCAL_ACCESS_KEY` in the server environment. The default endpoint is `https://api.myvocal.ai`. ## Send your first audio Each language page starts with a complete example that streams a file and prints the transcript: Blocking and `asyncio` clients. Blocking calls, `CompletableFuture` and listeners. `context.Context`, typed events and errors. ## Lifecycle, disconnects and errors The SDK frames audio (about 100 ms per frame), tracks sample cursors, follows in-connection rotation and ends the session when you call `finish`. The [behavior guide](/sdks/stt-realtime/behavior) covers `finish` vs `close`, disconnects, pause and resume, events, errors and observed service behavior. It applies to all three SDKs. # Real-time SDK — Python Source: https://wiz-myvocal.mintlify.app/sdks/stt-realtime/python Stream audio to MyVocal Speech to Text from Python 3.10+ with blocking or asyncio clients. `myvocal-stt-realtime` 1.0.0 is distributed as a wheel on the [GitHub Release](https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/tag/v1.0.0) (the sdist and `SHA256SUMS` are attached there too). Install it: ```bash theme={null} pip install https://github.com/MyVocal-AI/myvocal-stt-realtime-sdks/releases/download/v1.0.0/myvocal_stt_realtime-1.0.0-py3-none-any.whl ``` Python 3.10 or later. Dependencies: `httpx`, `websockets`. `RealtimeClient` (blocking) and `AsyncRealtimeClient` (`asyncio`) share one engine. ## Stream a file (blocking) ```python theme={null} import os from myvocal_stt_realtime import RealtimeClient, SessionOptions, SessionRequest request = SessionRequest(title="meeting", language_hint="en", options=SessionOptions(input_encoding="pcm_s16le_16000", segment_commit_mode="vad")) with RealtimeClient(os.environ["MYVOCAL_ACCESS_KEY"]) as client: session = client.connect(request, handlers={"transcript.final": lambda e: print("final:", e.text)}) try: session.send_file("speech.wav") # WAV header checked; paced by sample time result = session.finish() finally: session.close() # local resources only print(result.status, result.transcription_id, result.usage.billable_characters) ``` ## Byte chunks (asyncio) ```python theme={null} import asyncio, os from myvocal_stt_realtime import AsyncRealtimeClient, SessionOptions, SessionRequest async def main(chunks): async with AsyncRealtimeClient(os.environ["MYVOCAL_ACCESS_KEY"]) as client: session = await client.connect(SessionRequest(options=SessionOptions(input_encoding="pcm_s16le_16000")), iterate_events=True) async def printer(): async for event in session.events(): if event.type == "transcript.final": print(event.text) task = asyncio.ensure_future(printer()) async for chunk in chunks: # any size; a live source is not paced again await session.send_audio(chunk) result = await session.finish() await session.close() await task return result ``` ## Commit, pause and resume ```python theme={null} session.commit() # line boundary; same epoch session.pause() # or pause(via="rest") session.resume(via="ws") # new epoch; sample_offset restarts at 0 ``` ## After a disconnect ```python theme={null} from myvocal_stt_realtime import FinishUnconfirmedError try: result = session.finish() # REST close-out of the same session if needed if result.via_rest: print("closed out:", result.status, result.closeout_reason) except FinishUnconfirmedError as err: view = client.get_session(err.session_id) # later if not view.is_terminal: view = client.finish_session(err.session_id) ``` ## Client options | Keyword | Default | Meaning | | - | - | - | | `base_url` | `https://api.myvocal.ai` | `http`/`https`; the stream uses `ws`/`wss` | | `timeouts=Timeouts(...)` | see [behaviour guide](/sdks/stt-realtime/behavior#timeouts) | seconds | | `frame_ms`, `max_buffered_ms` | 100, 30000 | frame size and the bound of unacknowledged audio | | `ping_interval` | 20 | client WebSocket ping (seconds) | | `event_queue_size` | 10000 | bound of events waiting for handlers | | `proxy`, `ssl_context`, `http_client` (async only) | environment proxy, system CA | a borrowed `httpx.AsyncClient` is never closed | | `closeout_on_disconnect` | `True` | REST close-out after an unexpected disconnect | ## Errors `InputInvalidError`, `AuthenticationError` and `InsufficientCharactersError` are not retried. Other envelopes raise `ApiError` (`error_code`, `retryable`, `request_id`). Also: `AudioFormatError` (`discard_partial_sample()`), `SessionStateError`, `ConnectionLostError`, `BackpressureTimeoutError`, `FinishUnconfirmedError` (`session_id`) and `TransportError`.