{"info":{"title":"Typecast API","x-logo":{"url":"https://typecast.ai/_ipx/_/image/logo/tc_logo.webp"},"version":"0.1.2"},"paths":{"/v2/voices":{"get":{"tags":["Deprecated"],"x-mint":{"href":"/api-reference/deprecated/list-voices-v2"},"summary":"List Voices (v2)","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VoiceV2"},"title":"Response Get Voices"},"example":[{"age":"young_adult","gender":"female","models":[{"version":"ssfm-v30","emotions":["normal","happy","sad","angry","whisper","toneup","tonedown"]},{"version":"ssfm-v21","emotions":["normal","happy","sad","angry"]}],"voice_id":"tc_60e5426de8b95f1d3000d7b5","use_cases":["Audiobook","E-learning","Ads"],"voice_name":"Olivia","voice_type":"original"}]}},"description":"Success - Returns list of voice models with enhanced metadata"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Invalid or missing API key"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid request parameters"}},"deprecated":true,"parameters":[{"in":"query","name":"model","schema":{"$ref":"#/components/schemas/TTSModel"},"required":false,"description":"Filter by voice model (ssfm-v21 or ssfm-v30). Returns voices that support the specified model. Optional - if not provided, returns voices for all models."},{"in":"query","name":"gender","schema":{"$ref":"#/components/schemas/GenderEnum"},"required":false,"description":"Filter by gender (male or female). Returns voices matching the specified gender. Optional - if not provided, returns voices of all genders."},{"in":"query","name":"age","schema":{"$ref":"#/components/schemas/AgeEnum"},"required":false,"description":"Filter by age group (child, teenager, young_adult, middle_age, elder). Returns voices matching the specified age group. Optional - if not provided, returns voices of all ages."},{"in":"query","name":"use_cases","schema":{"$ref":"#/components/schemas/UseCasesEnum"},"required":false,"description":"Filter by use case category. Returns voices tagged with the specified use case (TikTok/Reels/Shorts, Game, Audiobook/Storytelling, etc.). Optional - if not provided, returns all voices regardless of use case."},{"in":"query","name":"voice_type","schema":{"$ref":"#/components/schemas/VoiceType"},"required":false,"description":"Filter by voice type (`original` or `custom`). Optional - if not provided, returns voices of all types."}],"description":"Lists all available voice models with enhanced metadata and filtering capabilities (V2).\n\nThis endpoint returns an enhanced voice list with model-grouped emotion support and additional metadata including gender, age group, and use cases. Each voice can support multiple models with their respective emotion sets.\n\n**Key Features:**\n- **Model Grouping**: Each voice includes a `models` array showing all supported TTS models and their available emotions\n- **Enhanced Metadata**: Includes gender (male/female), age group (child/teenager/young_adult/middle_age/elder), and use cases\n- **Advanced Filtering**: Filter by model, gender, age, and use cases to find voices matching specific requirements\n\n**Use Cases:**\n- Voice selection UI with demographic filters\n- Finding voices suitable for specific content types (e.g., Ads, Audiobook, eLearning)\n- Discovering which emotions are available for each model version","operationId":"get_voices_v2_v2_voices_get","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request GET \\\n  --url 'https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult' \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"C#","label":"C# (HttpClient)","source":"using System;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nvar client = new HttpClient();\nclient.DefaultRequestHeaders.Add(\"X-API-KEY\", \"<api-key>\");\n\nvar response = await client.GetAsync(\"https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult\");\n\nif (response.IsSuccessStatusCode)\n{\n    var content = await response.Content.ReadAsStringAsync();\n    Console.WriteLine(content);\n}\n"},{"lang":"Kotlin","label":"Kotlin (OkHttp)","source":"import okhttp3.OkHttpClient\nimport okhttp3.Request\n\nval client = OkHttpClient()\n\nval request = Request.Builder()\n    .url(\"https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult\")\n    .addHeader(\"X-API-KEY\", \"<api-key>\")\n    .get()\n    .build()\n\nclient.newCall(request).execute().use { response ->\n    if (response.isSuccessful) {\n        println(response.body?.string())\n    }\n}\n"},{"lang":"C++","label":"C++ (libcurl)","source":"#include <curl/curl.h>\n#include <string>\n#include <iostream>\n\nsize_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    ((std::string*)userp)->append((char*)contents, size * nmemb);\n    return size * nmemb;\n}\n\nint main() {\n    CURL* curl = curl_easy_init();\n    if(curl) {\n        std::string readBuffer;\n        struct curl_slist* headers = NULL;\n\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n        curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult\");\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);\n\n        CURLcode res = curl_easy_perform(curl);\n        if(res == CURLE_OK) {\n            std::cout << readBuffer << std::endl;\n        }\n\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n    }\n    return 0;\n}\n"},{"lang":"C","label":"C (libcurl)","source":"#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <curl/curl.h>\n\ntypedef struct {\n    char* data;\n    size_t size;\n} MemoryStruct;\n\nsize_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    size_t realsize = size * nmemb;\n    MemoryStruct* mem = (MemoryStruct*)userp;\n\n    char* ptr = realloc(mem->data, mem->size + realsize + 1);\n    if(!ptr) return 0;\n\n    mem->data = ptr;\n    memcpy(&(mem->data[mem->size]), contents, realsize);\n    mem->size += realsize;\n    mem->data[mem->size] = 0;\n\n    return realsize;\n}\n\nint main(void) {\n    CURL* curl;\n    CURLcode res;\n    MemoryStruct chunk = {NULL, 0};\n\n    curl_global_init(CURL_GLOBAL_ALL);\n    curl = curl_easy_init();\n\n    if(curl) {\n        struct curl_slist* headers = NULL;\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n        curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult\");\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);\n\n        res = curl_easy_perform(curl);\n\n        if(res == CURLE_OK) {\n            printf(\"%s\\n\", chunk.data);\n        }\n\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n        free(chunk.data);\n    }\n\n    curl_global_cleanup();\n    return 0;\n}\n"},{"lang":"Swift","label":"Swift (URLSession)","source":"import Foundation\n\nlet url = URL(string: \"https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult\")!\nvar request = URLRequest(url: url)\nrequest.httpMethod = \"GET\"\nrequest.setValue(\"<api-key>\", forHTTPHeaderField: \"X-API-KEY\")\n\nlet task = URLSession.shared.dataTask(with: request) { data, response, error in\n    if let data = data, let jsonString = String(data: data, encoding: .utf8) {\n        print(jsonString)\n    }\n}\ntask.resume()\n"},{"lang":"Rust","label":"Rust (reqwest)","source":"use reqwest;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let client = reqwest::Client::new();\n\n    let response = client\n        .get(\"https://api.typecast.ai/v2/voices?model=ssfm-v30&gender=female&age=young_adult\")\n        .header(\"X-API-KEY\", \"<api-key>\")\n        .send()\n        .await?;\n\n    if response.status().is_success() {\n        let body = response.text().await?;\n        println!(\"{}\", body);\n    }\n\n    Ok(())\n}\n"}]}},"/v3/voices":{"get":{"tags":["Voices"],"x-mint":{"href":"/api-reference/voices/list-voices"},"summary":"List Voices","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VoiceV3"},"title":"Response Get Voices V3 V3 Voices Get"},"example":[{"age":null,"gender":null,"models":[{"version":"ssfm-v30","emotions":["normal"]}],"voice_id":"uc_6700000000000000000000aa","use_cases":[],"voice_name":{"eng":"My Voice","kor":"내 보이스"},"voice_type":"custom","preview_url":null},{"age":"young_adult","gender":"female","models":[{"version":"ssfm-v30","emotions":["normal","happy","sad","angry"]}],"voice_id":"tc_6045d56d5f9ae03ac175cf73","use_cases":["Game","Anime"],"voice_name":{"eng":"Valkyrie","kor":"발키리"},"voice_type":"original","preview_url":"https://static2.typecast.ai/data/actor/valkyrie.mp3"}]}},"description":"Voices retrieved successfully"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid query parameter"}}},"description":"Validation Error - Invalid query parameter"}},"parameters":[{"in":"query","name":"model","schema":{"$ref":"#/components/schemas/TTSModel","description":"Filter by TTS model, such as `ssfm-v21`, `ssfm-v30`, or `ssfm-v31`."},"required":false,"description":"Filter by TTS model, such as `ssfm-v21`, `ssfm-v30`, or `ssfm-v31`."},{"in":"query","name":"gender","schema":{"$ref":"#/components/schemas/GenderEnum","description":"Filter by voice gender (`male` or `female`)."},"required":false,"description":"Filter by voice gender (`male` or `female`)."},{"in":"query","name":"age","schema":{"$ref":"#/components/schemas/AgeEnum","description":"Filter by age group (`child`, `teenager`, `young_adult`, `middle_age`, or `elder`)."},"required":false,"description":"Filter by age group (`child`, `teenager`, `young_adult`, `middle_age`, or `elder`)."},{"in":"query","name":"use_cases","schema":{"type":"string","title":"Use Cases","description":"Filter by a use-case keyword, such as `Ads`."},"required":false,"description":"Filter by a use-case keyword, such as `Ads`."},{"in":"query","name":"voice_type","schema":{"$ref":"#/components/schemas/VoiceType","description":"Filter by voice type (`original` or `custom`)."},"required":false,"description":"Filter by voice type (`original` or `custom`)."}],"description":"Lists the built-in voices and completed custom voices available for use with any endpoint that accepts a `voice_id`. Custom voices appear first. Each `voice_name` is keyed by ISO 639-3 language codes such as `eng` and `kor`.\r\n\r\nUse the optional filters together to narrow the catalog by model, gender, age group, use case, or voice type. `preview_url` is `null` when a preview is unavailable, including custom voices.","operationId":"get_voices_v3_v3_voices_get","x-codeSamples":[]}},"/v1/voices/clone":{"post":{"tags":["Deprecated"],"x-mint":{"href":"/api-reference/voices/instant-cloning"},"summary":"Instant Cloning (/v1/voices/clone)","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomVoiceResponse"},"example":{"name":"my-voice","model":"ssfm-v30","voice_id":"uc_64a1b2c3d4e5f6a7b8c9d0e1"}}},"description":"Successful Response - Custom voice created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"examples":{"audio_too_long":{"value":{"detail":"Audio duration exceeds maximum"},"summary":"Audio is longer than 150 seconds"},"file_too_large":{"value":{"detail":"File size exceeds maximum limit"},"summary":"File is too large"},"audio_too_short":{"value":{"detail":"Audio duration is below minimum"},"summary":"Audio is shorter than 5 seconds"},"audio_unreadable":{"value":{"detail":"Failed to read audio metadata"},"summary":"Audio metadata cannot be read"}}}},"description":"Bad Request - Invalid audio file, file size, duration, or other validation error"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Invalid or missing API key"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Voice cloning is not available on your plan"}}},"description":"Forbidden - Voice cloning is not available on your plan"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid request parameters"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Too many requests"}}},"description":"Too Many Requests - Rate limit or concurrency limit exceeded"}},"deprecated":true,"description":"Clone a custom voice from a short audio sample and use it like any built-in voice in subsequent text-to-speech calls.\n\nUpload a WAV or MP3 file (max 25 MB). The server extracts a speaker embedding and returns a custom voice ID with the `uc_` prefix that can be passed directly to `POST /v1/text-to-speech` (and any other endpoint that accepts a `voice_id`). The original audio is uploaded to S3 in the background after the response is returned.\n\n**Limits**\n\n- Audio file: max 25 MB. Supported formats: WAV, MP3.\n- Audio duration: 5 to 150 seconds.\n- Voice name: 1-30 characters.\n- Model: `ssfm-v21` or `ssfm-v30`. The cloned voice is bound to this engine model.\n- Each plan has a maximum number of active custom voices (the `custom_voice_slot`). Use `DELETE /v1/voices/{voice_id}` to free a slot.\n\n**Typical flow**\n\n1. `POST /v1/voices/clone` with the sample audio → receive `voice_id` (e.g. `uc_64a1b2...`).\n2. `POST /v1/text-to-speech` with `voice_id` set to the cloned ID.\n3. `DELETE /v1/voices/{voice_id}` when you no longer need the voice.","operationId":"create_voice_clone_v1_voices_clone_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_voice_clone_v1_voices_clone_post","type":"object","required":["file","name","model"],"properties":{"file":{"type":"string","format":"binary","description":"Audio sample. WAV or MP3, max 25 MB, 5-150 seconds."},"name":{"type":"string","maxLength":30,"minLength":1,"description":"Voice name (1-30 characters)."},"model":{"enum":["ssfm-v21","ssfm-v30"],"type":"string","description":"Engine model to clone the voice for."}}}}},"required":true},"x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request POST \\\n  --url 'https://api.typecast.ai/v1/voices/clone' \\\n  --header 'X-API-KEY: <api-key>' \\\n  -F 'file=@sample.wav' \\\n  -F 'name=my-voice' \\\n  -F 'model=ssfm-v30'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nwith open(\"sample.wav\", \"rb\") as f:\n    response = requests.post(\n        \"https://api.typecast.ai/v1/voices/clone\",\n        headers={\"X-API-KEY\": \"<api-key>\"},\n        files={\"file\": (\"sample.wav\", f, \"audio/wav\")},\n        data={\"name\": \"my-voice\", \"model\": \"ssfm-v30\"},\n    )\n\nprint(response.json())\n# {\"voice_id\": \"uc_64a1b2c3d4e5f6a7b8c9d0e1\", \"name\": \"my-voice\", \"model\": \"ssfm-v30\"}\n"}]}},"/v1/custom-voices":{"get":{"tags":["Custom Voices"],"x-mint":{"href":"/api-reference/custom-voices/list-custom-voices"},"summary":"List Custom Voices","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CustomVoiceItem"},"title":"Response List Custom Voices V1 Custom Voices Get"},"example":[{"name":"Product Narrator","error":null,"model":"ssfm-v30","source":"instant","status":"completed","voice_id":"uc_6700000000000000000000aa","created_at":"2026-08-26T04:15:00Z"},{"name":"Brand Voice","error":null,"model":"ssfm-v30","source":"professional","status":"training","voice_id":"uc_6700000000000000000000bb","created_at":"2026-08-26T04:20:00Z"}]}},"description":"Custom voices retrieved successfully"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"}},"description":"Lists all non-deleted custom voices owned by the authenticated account, including instant and professional clones. Results can include `pending`, `training`, `completed`, and `failed` voices.\n\nUse `status` to decide whether a voice is ready for synthesis. When `status` is `failed`, `error` contains a safe failure reason; otherwise it is `null`.","operationId":"list_custom_voices_v1_custom_voices_get","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request GET \\\n  --url https://api.typecast.ai/v1/custom-voices \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nresponse = requests.get(\n    \"https://api.typecast.ai/v1/custom-voices\",\n    headers={\"X-API-KEY\": \"<api-key>\"},\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"}]}},"/v1/text-to-speech":{"post":{"tags":["Text-to-Speech"],"x-mint":{"href":"/api-reference/text-to-speech/text-to-speech"},"summary":"Text To Speech","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"content":{"audio/wav":{"schema":{"type":"string","format":"binary","description":"WAV audio file binary data. Uncompressed PCM audio with 16-bit depth, mono channel, 44100 Hz sample rate."},"example":"[Binary audio data - WAV file content]"}},"description":"Success - Returns audio file"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid voice_id"}}},"description":"Bad Request - Invalid parameters"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Authentication failed"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Insufficient credit"}}},"description":"Payment Required - Insufficient credits"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Voice not found"}}},"description":"Not Found - Voice model not available"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text.","error_code":"TEXT_NOT_SYNTHESIZABLE"}}},"description":"Validation Error - The request is invalid or the input text cannot be synthesized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Too many requests"}}},"description":"Too Many Requests - Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"An unexpected error occurred"}}},"description":"Internal Server Error - Server processing failed"}},"deprecated":false,"description":"Generate speech from text using the specified voice model. Supports emotion, volume, pitch, and tempo customization.\r\n\r\nFirst, list all available voice models using the GET /v3/voices endpoint,  then use the voice\\_id from the response to generate speech with this endpoint. Each voice model has its own unique characteristics. See [Listing all voices](/docs/api-reference/voices/list-voices) for available voices.","operationId":"text_to_speech_v1_text_to_speech_post","requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"TTSRequest","required":["text","model","voice_id"],"properties":{"text":{"type":"string","title":"Text","example":"Everything is so incredibly perfect that I feel like I'm dreaming.","maxLength":2000,"minLength":1,"description":"Text to convert to speech. Minimum 1 character, maximum 2000 characters. Credits consumed based on text length. Supports multiple languages including English, Korean, Japanese, and Chinese. Special characters and punctuation are handled automatically."},"model":{"$ref":"#/components/schemas/TTSModel","example":"ssfm-v30","description":"Voice model to use for speech synthesis.\r\n\r\n* **ssfm-v30**: Latest model with improved prosody and additional emotion presets (recommended)\r\n* **ssfm-v21**: Stable production model with reliable quality"},"output":{"type":"object","title":"","properties":{"volume":{"anyOf":[{"type":"integer","maximum":200,"minimum":0},{"type":"null"}],"title":"Volume","example":100,"description":"Adjusts the relative volume of the output audio: 0 (completely silent), 50 (half volume), 100 (standard volume, default), 150 (50% louder than standard), 200 (maximum volume, twice as loud as standard).\r\n\r\nSince this only scales the existing volume, using `volume` can amplify the loudness differences between voices if they have different baseline levels. For consistent output across all clips, use `target_lufs` instead.\r\n\r\n- **Note:** This parameter cannot be used simultaneously with the `target_lufs` parameter.\r\n\r\nRequired range: 0 <= x <= 200\r\n"},"audio_pitch":{"type":"integer","title":"Audio Pitch","default":0,"example":0,"maximum":12,"minimum":-12,"description":"Adjusts the pitch in semitones to affect perceived gender and age: -12 (one octave lower, deeper voice), -6 (half octave lower), 0 (original pitch, default), +6 (half octave higher), +12 (one octave higher, higher voice)"},"audio_tempo":{"type":"number","title":"Audio Tempo","default":1,"example":1,"maximum":2,"minimum":0.5,"description":"Controls speech speed: 0.5 (half speed, very slow and clear), 0.75 (slightly slower than normal), 1.0 (normal speaking speed, default), 1.5 (50% faster than normal), 2.0 (double speed, very fast speech)"},"target_lufs":{"anyOf":[{"type":"number","maximum":0,"minimum":-70},{"type":"null"}],"title":"Target Lufs","example":-14,"description":"Sets the target absolute loudness (LUFS) for the output audio. This normalizes all generated voices to a consistent volume level, regardless of the original source's loudness. Values closer to 0 are louder, while values closer to -70 are quieter.\r\n\r\n- Required range: -70 <= x <= 0\r\n- Recommended values: -14 (common streaming standard), -23 (broadcast standard)\r\n- **Note:** This parameter cannot be used simultaneously with the `volume` parameter. Use `target_lufs` for consistent absolute loudness across different clips, or use `volume` for traditional relative scaling.\r\n"},"audio_format":{"enum":["wav","mp3"],"type":"string","title":"Audio Format","default":"wav","example":"wav","description":"Output audio format.\r\n\r\n**WAV format:**\r\n- Uncompressed PCM audio\r\n- 16-bit depth, mono channel, 44100 Hz sample rate\r\n- Higher quality, larger file size\r\n- Recommended for professional audio production\r\n\r\n**MP3 format:**\r\n- Compressed MPEG Layer III audio\r\n- 320 kbps bitrate, 44100 Hz sample rate\r\n- Smaller file size\r\n- Recommended for web streaming and distribution\r\n"},"remove_silence_ms":{"anyOf":[{"type":"integer","maximum":1000,"minimum":0},{"type":"null"}],"title":"Remove Silence Ms","default":null,"example":100,"description":"When enabled, shortens detected silences longer than the specified duration to that duration. The value is in milliseconds (ms). The value is the duration of silence to retain, not the amount to remove.\r\n\r\n**Accepted values:**\r\n\r\n- An integer from **0 to 1000**, with a recommended range of 0 to 200.\r\n- Omitted or `null`: silence removal is disabled.\r\n- `0`: removes detected silence longer than 0 ms. **This does not disable the feature.**\r\n- Booleans, strings, fractional values, and out-of-range values are invalid.\r\n\r\n**Example:** `100` shortens detected silences longer than 100 ms to 100 ms. Lower values include shorter silence segments for removal and leave less silence in each affected segment."}},"description":"Audio output settings including volume (0-200), pitch (-12 to +12 semitones), tempo (0.5x to 2.0x), and format (wav/mp3) for controlling the final audio characteristics"},"prompt":{"oneOf":[{"$ref":"#/components/schemas/SmartPrompt"},{"$ref":"#/components/schemas/PresetPrompt"},{"$ref":"#/components/schemas/Prompt"}],"title":"Prompt","description":"Emotion and style settings for the generated speech, including emotion type (happy/sad/angry/normal) and intensity (0.0 to 2.0) to control the emotional expression"},"language":{"type":"string","title":"Language","example":"eng","description":"Language code following ISO 639-3 standard. Case-insensitive (both \"ENG\" and \"eng\" are accepted). If not provided, will be auto-detected based on text content.\r\n\r\n<details>\r\n  <summary><strong>ssfm-v30 Supported Languages (37)</strong></summary>\r\n\r\n  | Code | Language  | Code | Language   | Code | Language   |\r\n  | ---- | --------- | ---- | ---------- | ---- | ---------- |\r\n  | ARA  | Arabic    | IND  | Indonesian | POR  | Portuguese |\r\n  | BEN  | Bengali   | ITA  | Italian    | RON  | Romanian   |\r\n  | BUL  | Bulgarian | JPN  | Japanese   | RUS  | Russian    |\r\n  | CES  | Czech     | KOR  | Korean     | SLK  | Slovak     |\r\n  | DAN  | Danish    | MSA  | Malay      | SPA  | Spanish    |\r\n  | DEU  | German    | NAN  | Min Nan    | SWE  | Swedish    |\r\n  | ELL  | Greek     | NLD  | Dutch      | TAM  | Tamil      |\r\n  | ENG  | English   | NOR  | Norwegian  | TGL  | Tagalog    |\r\n  | FIN  | Finnish   | PAN  | Punjabi    | THA  | Thai       |\r\n  | FRA  | French    | POL  | Polish     | TUR  | Turkish    |\r\n  | HIN  | Hindi     | UKR  | Ukrainian  | VIE  | Vietnamese |\r\n  | HRV  | Croatian  | YUE  | Cantonese  | ZHO  | Chinese    |\r\n  | HUN  | Hungarian |      |            |      |            |\r\n</details>\r\n\r\n<details>\r\n  <summary><strong>ssfm-v21 Supported Languages (27)</strong></summary>\r\n\r\n  | Code | Language  | Code | Language   | Code | Language  |\r\n  | ---- | --------- | ---- | ---------- | ---- | --------- |\r\n  | ARA  | Arabic    | IND  | Indonesian | RON  | Romanian  |\r\n  | BUL  | Bulgarian | ITA  | Italian    | RUS  | Russian   |\r\n  | CES  | Czech     | JPN  | Japanese   | SLK  | Slovak    |\r\n  | DAN  | Danish    | KOR  | Korean     | SPA  | Spanish   |\r\n  | DEU  | German    | MSA  | Malay      | SWE  | Swedish   |\r\n  | ELL  | Greek     | NLD  | Dutch      | TAM  | Tamil     |\r\n  | ENG  | English   | POL  | Polish     | TGL  | Tagalog   |\r\n  | FIN  | Finnish   | POR  | Portuguese | UKR  | Ukrainian |\r\n  | FRA  | French    | HRV  | Croatian   | ZHO  | Chinese   |\r\n</details>"},"voice_id":{"type":"string","title":"Voice Id","example":"tc_60e5426de8b95f1d3000d7b5","description":"Voice identifier. Two prefixes are supported:\r\n\r\n* `tc_` — Built-in Typecast voices (e.g., `tc_60e5426de8b95f1d3000d7b5`). See [Listing all voices](/docs/api-reference/voices/list-voices) for available IDs.\r\n* `uc_` — Custom voices created via [Instant cloning](/docs/api-reference/voices/instant-cloning) (e.g., `uc_64a1b2c3d4e5f6a7b8c9d0e1`). Only the owner of a cloned voice can use it.\r\n\r\nCase-sensitive: must use lowercase prefix."}},"description":"Text-to-speech request parameters"}}},"required":true,"description":""},"x-codeSamples":[{"lang":"cURL","label":"cURL (save to file)","source":"curl --request POST \\\r\n  --url https://api.typecast.ai/v1/text-to-speech \\\r\n  --header 'Content-Type: application/json' \\\r\n  --header 'X-API-KEY: <api-key>' \\\r\n  --output output.wav \\\r\n  --data @- <<EOF\r\n{\r\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n  \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n  \"model\": \"ssfm-v30\",\r\n  \"language\": \"eng\",\r\n  \"prompt\": {\r\n    \"emotion_type\": \"smart\",\r\n    \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n    \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n  },\r\n  \"output\": {\r\n    \"volume\": 100,\r\n    \"audio_pitch\": 0,\r\n    \"audio_tempo\": 1,\r\n    \"audio_format\": \"wav\"\r\n  }\r\n}\r\nEOF\r\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\r\n\r\nAPI_HOST = \"https://api.typecast.ai\"\r\nheaders = {\r\n    \"X-API-KEY\": \"<api-key>\",\r\n    \"Content-Type\": \"application/json\"\r\n}\r\npayload = {\r\n    \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n    \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n    \"model\": \"ssfm-v30\",\r\n    \"language\": \"eng\",\r\n    \"prompt\": {\r\n        \"emotion_type\": \"smart\",\r\n        \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n        \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n    },\r\n    \"output\": {\r\n        \"volume\": 100,\r\n        \"audio_pitch\": 0,\r\n        \"audio_tempo\": 1,\r\n        \"audio_format\": \"wav\"\r\n    }\r\n}\r\n\r\nresponse = requests.post(f\"{API_HOST}/v1/text-to-speech\", headers=headers, json=payload, timeout=60)\r\nresponse.raise_for_status()\r\n\r\nwith open(\"output.wav\", \"wb\") as f:\r\n    f.write(response.content)\r\nprint(f\"Saved {len(response.content)} bytes to output.wav\")\r\n"},{"lang":"C#","label":"C# (HttpClient)","source":"using System;\r\nusing System.Net.Http;\r\nusing System.Text;\r\nusing System.Threading.Tasks;\r\n\r\nvar client = new HttpClient();\r\nclient.DefaultRequestHeaders.Add(\"X-API-KEY\", \"<api-key>\");\r\n\r\nvar requestBody = @\"{\r\n  \"\"voice_id\"\": \"\"tc_60e5426de8b95f1d3000d7b5\"\",\r\n  \"\"text\"\": \"\"Everything is so incredibly perfect that I feel like I'm dreaming.\"\",\r\n  \"\"model\"\": \"\"ssfm-v30\"\",\r\n  \"\"language\"\": \"\"eng\"\",\r\n  \"\"prompt\"\": {\r\n    \"\"emotion_type\"\": \"\"smart\"\",\r\n    \"\"previous_text\"\": \"\"I feel like I'm walking on air and I just want to scream with joy!\"\",\r\n    \"\"next_text\"\": \"\"I am literally bursting with happiness and I never want this feeling to end!\"\"\r\n  },\r\n  \"\"output\"\": {\r\n    \"\"volume\"\": 100,\r\n    \"\"audio_pitch\"\": 0,\r\n    \"\"audio_tempo\"\": 1,\r\n    \"\"audio_format\"\": \"\"wav\"\"\r\n  }\r\n}\";\r\n\r\nvar content = new StringContent(requestBody, Encoding.UTF8, \"application/json\");\r\nvar response = await client.PostAsync(\"https://api.typecast.ai/v1/text-to-speech\", content);\r\n\r\nif (response.IsSuccessStatusCode)\r\n{\r\n    var audioBytes = await response.Content.ReadAsByteArrayAsync();\r\n    await File.WriteAllBytesAsync(\"output.wav\", audioBytes);\r\n    Console.WriteLine(\"Audio saved to output.wav\");\r\n}\r\n"},{"lang":"Kotlin","label":"Kotlin (OkHttp)","source":"import okhttp3.MediaType.Companion.toMediaType\r\nimport okhttp3.OkHttpClient\r\nimport okhttp3.Request\r\nimport okhttp3.RequestBody.Companion.toRequestBody\r\nimport java.io.File\r\n\r\nval client = OkHttpClient()\r\nval mediaType = \"application/json\".toMediaType()\r\n\r\nval requestBody = \"\"\"\r\n{\r\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n  \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n  \"model\": \"ssfm-v30\",\r\n  \"language\": \"eng\",\r\n  \"prompt\": {\r\n    \"emotion_type\": \"smart\",\r\n    \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n    \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n  },\r\n  \"output\": {\r\n    \"volume\": 100,\r\n    \"audio_pitch\": 0,\r\n    \"audio_tempo\": 1,\r\n    \"audio_format\": \"wav\"\r\n  }\r\n}\r\n\"\"\".trimIndent()\r\n\r\nval request = Request.Builder()\r\n    .url(\"https://api.typecast.ai/v1/text-to-speech\")\r\n    .addHeader(\"X-API-KEY\", \"<api-key>\")\r\n    .addHeader(\"Content-Type\", \"application/json\")\r\n    .post(requestBody.toRequestBody(mediaType))\r\n    .build()\r\n\r\nclient.newCall(request).execute().use { response ->\r\n    if (response.isSuccessful) {\r\n        response.body?.bytes()?.let {\r\n            File(\"output.wav\").writeBytes(it)\r\n            println(\"Audio saved to output.wav\")\r\n        }\r\n    }\r\n}\r\n"},{"lang":"C++","label":"C++ (libcurl)","source":"#include <curl/curl.h>\r\n#include <fstream>\r\n#include <string>\r\n\r\nsize_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {\r\n    ((std::string*)userp)->append((char*)contents, size * nmemb);\r\n    return size * nmemb;\r\n}\r\n\r\nint main() {\r\n    CURL* curl = curl_easy_init();\r\n    if(curl) {\r\n        std::string readBuffer;\r\n        struct curl_slist* headers = NULL;\r\n\r\n        headers = curl_slist_append(headers, \"Content-Type: application/json\");\r\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\r\n\r\n        std::string jsonData = R\"({\r\n          \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n          \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n          \"model\": \"ssfm-v30\",\r\n          \"language\": \"eng\",\r\n          \"prompt\": {\r\n            \"emotion_type\": \"smart\",\r\n            \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n            \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n          },\r\n          \"output\": {\r\n            \"volume\": 100,\r\n            \"audio_pitch\": 0,\r\n            \"audio_tempo\": 1,\r\n            \"audio_format\": \"wav\"\r\n          }\r\n        })\";\r\n\r\n        curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v1/text-to-speech\");\r\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\r\n        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData.c_str());\r\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\r\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);\r\n\r\n        CURLcode res = curl_easy_perform(curl);\r\n        if(res == CURLE_OK) {\r\n            std::ofstream outFile(\"output.wav\", std::ios::binary);\r\n            outFile.write(readBuffer.c_str(), readBuffer.size());\r\n            outFile.close();\r\n        }\r\n\r\n        curl_slist_free_all(headers);\r\n        curl_easy_cleanup(curl);\r\n    }\r\n    return 0;\r\n}\r\n"},{"lang":"C","label":"C (libcurl)","source":"#include <stdio.h>\r\n#include <stdlib.h>\r\n#include <string.h>\r\n#include <curl/curl.h>\r\n\r\ntypedef struct {\r\n    char* data;\r\n    size_t size;\r\n} MemoryStruct;\r\n\r\nsize_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, void* userp) {\r\n    size_t realsize = size * nmemb;\r\n    MemoryStruct* mem = (MemoryStruct*)userp;\r\n\r\n    char* ptr = realloc(mem->data, mem->size + realsize + 1);\r\n    if(!ptr) return 0;\r\n\r\n    mem->data = ptr;\r\n    memcpy(&(mem->data[mem->size]), contents, realsize);\r\n    mem->size += realsize;\r\n    mem->data[mem->size] = 0;\r\n\r\n    return realsize;\r\n}\r\n\r\nint main(void) {\r\n    CURL* curl;\r\n    CURLcode res;\r\n    MemoryStruct chunk = {NULL, 0};\r\n\r\n    curl_global_init(CURL_GLOBAL_ALL);\r\n    curl = curl_easy_init();\r\n\r\n    if(curl) {\r\n        struct curl_slist* headers = NULL;\r\n        headers = curl_slist_append(headers, \"Content-Type: application/json\");\r\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\r\n\r\n        const char* jsonData = \"{\"\r\n            \"\\\"voice_id\\\":\\\"tc_60e5426de8b95f1d3000d7b5\\\",\"\r\n            \"\\\"text\\\":\\\"Everything is so incredibly perfect that I feel like I'm dreaming.\\\",\"\r\n            \"\\\"model\\\":\\\"ssfm-v30\\\",\"\r\n            \"\\\"language\\\":\\\"eng\\\",\"\r\n            \"\\\"output\\\":{\\\"volume\\\":100,\\\"audio_pitch\\\":0,\\\"audio_tempo\\\":1,\\\"audio_format\\\":\\\"wav\\\"}\"\r\n            \"}\";\r\n\r\n        curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v1/text-to-speech\");\r\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\r\n        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonData);\r\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);\r\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);\r\n\r\n        res = curl_easy_perform(curl);\r\n\r\n        if(res == CURLE_OK) {\r\n            FILE* fp = fopen(\"output.wav\", \"wb\");\r\n            fwrite(chunk.data, 1, chunk.size, fp);\r\n            fclose(fp);\r\n        }\r\n\r\n        curl_slist_free_all(headers);\r\n        curl_easy_cleanup(curl);\r\n        free(chunk.data);\r\n    }\r\n\r\n    curl_global_cleanup();\r\n    return 0;\r\n}\r\n"},{"lang":"Swift","label":"Swift (URLSession)","source":"import Foundation\r\n\r\nlet url = URL(string: \"https://api.typecast.ai/v1/text-to-speech\")!\r\nvar request = URLRequest(url: url)\r\nrequest.httpMethod = \"POST\"\r\nrequest.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\r\nrequest.setValue(\"<api-key>\", forHTTPHeaderField: \"X-API-KEY\")\r\n\r\nlet requestBody: [String: Any] = [\r\n    \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n    \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n    \"model\": \"ssfm-v30\",\r\n    \"language\": \"eng\",\r\n    \"prompt\": [\r\n        \"emotion_type\": \"smart\",\r\n        \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n        \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n    ],\r\n    \"output\": [\r\n        \"volume\": 100,\r\n        \"audio_pitch\": 0,\r\n        \"audio_tempo\": 1,\r\n        \"audio_format\": \"wav\"\r\n    ]\r\n]\r\n\r\nrequest.httpBody = try? JSONSerialization.data(withJSONObject: requestBody)\r\n\r\nlet task = URLSession.shared.dataTask(with: request) { data, response, error in\r\n    if let data = data {\r\n        try? data.write(to: URL(fileURLWithPath: \"output.wav\"))\r\n        print(\"Audio saved to output.wav\")\r\n    }\r\n}\r\ntask.resume()\r\n"},{"lang":"Rust","label":"Rust (reqwest)","source":"use reqwest;\r\nuse serde_json::json;\r\nuse std::fs::File;\r\nuse std::io::Write;\r\n\r\n#[tokio::main]\r\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\r\n    let client = reqwest::Client::new();\r\n\r\n    let request_body = json!({\r\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n        \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n        \"model\": \"ssfm-v30\",\r\n        \"language\": \"eng\",\r\n        \"prompt\": {\r\n            \"emotion_type\": \"smart\",\r\n            \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n            \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n        },\r\n        \"output\": {\r\n            \"volume\": 100,\r\n            \"audio_pitch\": 0,\r\n            \"audio_tempo\": 1,\r\n            \"audio_format\": \"wav\"\r\n        }\r\n    });\r\n\r\n    let response = client\r\n        .post(\"https://api.typecast.ai/v1/text-to-speech\")\r\n        .header(\"X-API-KEY\", \"<api-key>\")\r\n        .header(\"Content-Type\", \"application/json\")\r\n        .json(&request_body)\r\n        .send()\r\n        .await?;\r\n\r\n    if response.status().is_success() {\r\n        let bytes = response.bytes().await?;\r\n        let mut file = File::create(\"output.wav\")?;\r\n        file.write_all(&bytes)?;\r\n        println!(\"Audio saved to output.wav\");\r\n    }\r\n\r\n    Ok(())\r\n}\r\n"},{"lang":"JavaScript","label":"JavaScript (Node.js)","source":"// Node 18+ (built-in fetch).\r\nimport { writeFile } from \"node:fs/promises\";\r\n\r\nconst response = await fetch(\"https://api.typecast.ai/v1/text-to-speech\", {\r\n    method: \"POST\",\r\n    headers: {\r\n        \"Content-Type\": \"application/json\",\r\n        \"X-API-KEY\": \"<api-key>\"\r\n    },\r\n    body: JSON.stringify({\r\n        voice_id: \"tc_60e5426de8b95f1d3000d7b5\",\r\n        text: \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n        model: \"ssfm-v30\",\r\n        language: \"eng\",\r\n        prompt: {\r\n            emotion_type: \"smart\",\r\n            previous_text: \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n            next_text: \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n        },\r\n        output: { volume: 100, audio_pitch: 0, audio_tempo: 1, audio_format: \"wav\" }\r\n    })\r\n});\r\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\r\n\r\nconst buffer = Buffer.from(await response.arrayBuffer());\r\nawait writeFile(\"output.wav\", buffer);\r\nconsole.log(`Saved ${buffer.length} bytes to output.wav`);\r\n"},{"lang":"PHP","label":"PHP (curl)","source":"<?php\r\n$payload = json_encode([\r\n    \"voice_id\" => \"tc_60e5426de8b95f1d3000d7b5\",\r\n    \"text\" => \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n    \"model\" => \"ssfm-v30\",\r\n    \"language\" => \"eng\",\r\n    \"prompt\" => [\r\n        \"emotion_type\" => \"smart\",\r\n        \"previous_text\" => \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n        \"next_text\" => \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n    ],\r\n    \"output\" => [\"volume\" => 100, \"audio_pitch\" => 0, \"audio_tempo\" => 1, \"audio_format\" => \"wav\"]\r\n]);\r\n\r\n$ch = curl_init(\"https://api.typecast.ai/v1/text-to-speech\");\r\ncurl_setopt_array($ch, [\r\n    CURLOPT_POST => true,\r\n    CURLOPT_RETURNTRANSFER => true,\r\n    CURLOPT_HTTPHEADER => [\r\n        \"Content-Type: application/json\",\r\n        \"X-API-KEY: <api-key>\"\r\n    ],\r\n    CURLOPT_POSTFIELDS => $payload\r\n]);\r\n$audio = curl_exec($ch);\r\n$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);\r\nif ($status !== 200) {\r\n    fwrite(STDERR, \"HTTP $status\\n\");\r\n    exit(1);\r\n}\r\nfile_put_contents(\"output.wav\", $audio);\r\necho \"Saved \" . strlen($audio) . \" bytes to output.wav\\n\";\r\n"},{"lang":"Go","label":"Go (net/http)","source":"package main\r\n\r\nimport (\r\n    \"bytes\"\r\n    \"fmt\"\r\n    \"io\"\r\n    \"net/http\"\r\n    \"os\"\r\n)\r\n\r\nfunc main() {\r\n    body := []byte(`{\r\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n        \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n        \"model\": \"ssfm-v30\",\r\n        \"language\": \"eng\",\r\n        \"prompt\": {\r\n            \"emotion_type\": \"smart\",\r\n            \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n            \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n        },\r\n        \"output\": {\"volume\": 100, \"audio_pitch\": 0, \"audio_tempo\": 1, \"audio_format\": \"wav\"}\r\n    }`)\r\n\r\n    req, _ := http.NewRequest(\"POST\", \"https://api.typecast.ai/v1/text-to-speech\", bytes.NewReader(body))\r\n    req.Header.Set(\"Content-Type\", \"application/json\")\r\n    req.Header.Set(\"X-API-KEY\", \"<api-key>\")\r\n\r\n    resp, err := http.DefaultClient.Do(req)\r\n    if err != nil {\r\n        panic(err)\r\n    }\r\n    defer resp.Body.Close()\r\n\r\n    out, _ := os.Create(\"output.wav\")\r\n    defer out.Close()\r\n    n, _ := io.Copy(out, resp.Body)\r\n    fmt.Printf(\"Saved %d bytes to output.wav\\n\", n)\r\n}\r\n"},{"lang":"Java","label":"Java (HttpClient)","source":"// Java 11+ HttpClient with file body handler.\r\nimport java.net.URI;\r\nimport java.net.http.HttpClient;\r\nimport java.net.http.HttpRequest;\r\nimport java.net.http.HttpResponse;\r\nimport java.nio.file.Path;\r\n\r\npublic class TextToSpeech {\r\n    public static void main(String[] args) throws Exception {\r\n        String body = \"\"\"\r\n            {\r\n              \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n              \"text\": \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n              \"model\": \"ssfm-v30\",\r\n              \"language\": \"eng\",\r\n              \"prompt\": {\r\n                \"emotion_type\": \"smart\",\r\n                \"previous_text\": \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n                \"next_text\": \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n              },\r\n              \"output\": {\"volume\": 100, \"audio_pitch\": 0, \"audio_tempo\": 1, \"audio_format\": \"wav\"}\r\n            }\r\n            \"\"\";\r\n\r\n        HttpRequest request = HttpRequest.newBuilder()\r\n                .uri(URI.create(\"https://api.typecast.ai/v1/text-to-speech\"))\r\n                .header(\"Content-Type\", \"application/json\")\r\n                .header(\"X-API-KEY\", \"<api-key>\")\r\n                .POST(HttpRequest.BodyPublishers.ofString(body))\r\n                .build();\r\n\r\n        HttpResponse<Path> response = HttpClient.newHttpClient()\r\n                .send(request, HttpResponse.BodyHandlers.ofFile(Path.of(\"output.wav\")));\r\n\r\n        System.out.println(\"Audio saved to \" + response.body());\r\n    }\r\n}\r\n"},{"lang":"Ruby","label":"Ruby (net/http)","source":"require \"net/http\"\r\nrequire \"uri\"\r\nrequire \"json\"\r\n\r\nuri = URI(\"https://api.typecast.ai/v1/text-to-speech\")\r\nhttp = Net::HTTP.new(uri.host, uri.port)\r\nhttp.use_ssl = true\r\n\r\nreq = Net::HTTP::Post.new(uri)\r\nreq[\"Content-Type\"] = \"application/json\"\r\nreq[\"X-API-KEY\"] = \"<api-key>\"\r\nreq.body = {\r\n  voice_id: \"tc_60e5426de8b95f1d3000d7b5\",\r\n  text: \"Everything is so incredibly perfect that I feel like I'm dreaming.\",\r\n  model: \"ssfm-v30\",\r\n  language: \"eng\",\r\n  prompt: {\r\n    emotion_type: \"smart\",\r\n    previous_text: \"I feel like I'm walking on air and I just want to scream with joy!\",\r\n    next_text: \"I am literally bursting with happiness and I never want this feeling to end!\"\r\n  },\r\n  output: { volume: 100, audio_pitch: 0, audio_tempo: 1, audio_format: \"wav\" }\r\n}.to_json\r\n\r\nresp = http.request(req)\r\nraise \"HTTP #{resp.code}\" unless resp.code == \"200\"\r\n\r\nFile.binwrite(\"output.wav\", resp.body)\r\nputs \"Saved #{resp.body.bytesize} bytes to output.wav\"\r\n"},{"lang":"cURL","label":"Silence removal","source":"curl --request POST 'https://api.typecast.ai/v1/text-to-speech' \\\r\n  --header 'X-API-KEY: <api-key>' \\\r\n  --header 'Content-Type: application/json' \\\r\n  --output review.wav \\\r\n  --data-binary @- <<'JSON'\r\n{\r\n  \"voice_id\": \"<voice-id>\",\r\n  \"text\": \"Hello. Thank you for listening.\",\r\n  \"model\": \"ssfm-v30\",\r\n  \"output\": {\r\n    \"audio_format\": \"wav\",\r\n    \"remove_silence_ms\": 300\r\n  }\r\n}\r\nJSON\r\n"}]}},"/v1/voices/{voice_id}":{"delete":{"tags":["Deprecated"],"x-mint":{"href":"/api-reference/voices/delete-custom-voice"},"summary":"Delete Custom Voice (/v1/voices/{voice_id})","responses":{"204":{"description":"No Content - Voice deleted successfully. The response body is intentionally empty per RFC 9110; treat any 2xx status as success."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Invalid or missing API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Voice not found"}}},"description":"Not Found - Voice does not exist or is not owned by the caller"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid voice_id format"}},"deprecated":true,"parameters":[{"in":"path","name":"voice_id","schema":{"type":"string","example":"uc_64a1b2c3d4e5f6a7b8c9d0e1","pattern":"^uc_[A-Za-z0-9]+$"},"required":true,"description":"Custom voice identifier with the `uc_` prefix."}],"description":"Soft-delete a custom voice that was created via `POST /v1/voices/clone`. The voice is removed from your active set and the corresponding `custom_voice_slot` becomes available for a new clone.\n\nAfter deletion, the same `voice_id` returns 404 on subsequent requests. Only the owner of the voice may delete it; other users receive 404.\n\nReturns 204 No Content on success.","operationId":"delete_custom_voice_v1_voices__voice_id__delete"}},"/v2/voices/{voice_id}":{"get":{"tags":["Deprecated"],"x-mint":{"href":"/api-reference/deprecated/get-voice-details-v2"},"summary":"Get Voice Details (v2)","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceV2"},"example":{"age":"young_adult","gender":"female","models":[{"version":"ssfm-v30","emotions":["normal","happy","sad","angry","whisper","toneup","tonedown"]},{"version":"ssfm-v21","emotions":["normal","happy","sad","angry"]}],"voice_id":"tc_60e5426de8b95f1d3000d7b5","use_cases":["Audiobook","E-learning","Ads"],"voice_name":"Olivia","voice_type":"original"}}},"description":"Success - Returns detailed information for the requested voice"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Invalid or missing API key"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Voice not found"}}},"description":"Not Found - Requested voice does not exist"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid voice_id format"}},"deprecated":true,"parameters":[{"in":"path","name":"voice_id","schema":{"type":"string","title":"Voice Id"},"required":true}],"description":"Retrieves detailed information for a specific voice with enhanced metadata (V2).\n\nThis endpoint returns the complete information for a single voice, including model-grouped emotion support and metadata such as gender, age group, and use cases. Use this when you need to verify voice details or check available emotions before making a TTS request.\n\n**Response includes:**\n- **voice_id**: Unique voice identifier\n- **voice_name**: Human-readable voice name\n- **models**: Array of supported TTS models with their respective emotion sets\n- **gender**: Voice gender classification (male/female)\n- **age**: Age group classification (child/teenager/young_adult/middle_age/elder)\n- **use_cases**: Recommended content categories for this voice\n\n**Use Cases:**\n- Verify voice availability before TTS request\n- Check supported emotions for a specific voice and model combination\n- Display voice details in a voice selection UI","operationId":"get_voice_v2_v2_voices__voice_id__get","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request GET \\\n  --url 'https://api.typecast.ai/v2/voices/tc_60e5426de8b95f1d3000d7b5' \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"C#","label":"C# (HttpClient)","source":"using System;\nusing System.Net.Http;\nusing System.Threading.Tasks;\n\nvar client = new HttpClient();\nclient.DefaultRequestHeaders.Add(\"X-API-KEY\", \"<api-key>\");\n\nvar voiceId = \"tc_60e5426de8b95f1d3000d7b5\";\nvar response = await client.GetAsync($\"https://api.typecast.ai/v2/voices/{voiceId}\");\n\nif (response.IsSuccessStatusCode)\n{\n    var content = await response.Content.ReadAsStringAsync();\n    Console.WriteLine(content);\n}\n"},{"lang":"Kotlin","label":"Kotlin (OkHttp)","source":"import okhttp3.OkHttpClient\nimport okhttp3.Request\n\nval client = OkHttpClient()\nval voiceId = \"tc_60e5426de8b95f1d3000d7b5\"\n\nval request = Request.Builder()\n    .url(\"https://api.typecast.ai/v2/voices/$voiceId\")\n    .addHeader(\"X-API-KEY\", \"<api-key>\")\n    .get()\n    .build()\n\nclient.newCall(request).execute().use { response ->\n    if (response.isSuccessful) {\n        println(response.body?.string())\n    }\n}\n"},{"lang":"C++","label":"C++ (libcurl)","source":"#include <curl/curl.h>\n#include <string>\n#include <iostream>\n\nsize_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    ((std::string*)userp)->append((char*)contents, size * nmemb);\n    return size * nmemb;\n}\n\nint main() {\n    CURL* curl = curl_easy_init();\n    if(curl) {\n        std::string readBuffer;\n        struct curl_slist* headers = NULL;\n\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n        std::string url = \"https://api.typecast.ai/v2/voices/tc_60e5426de8b95f1d3000d7b5\";\n\n        curl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);\n\n        CURLcode res = curl_easy_perform(curl);\n        if(res == CURLE_OK) {\n            std::cout << readBuffer << std::endl;\n        }\n\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n    }\n    return 0;\n}\n"},{"lang":"C","label":"C (libcurl)","source":"#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <curl/curl.h>\n\ntypedef struct {\n    char* data;\n    size_t size;\n} MemoryStruct;\n\nsize_t WriteMemoryCallback(void* contents, size_t size, size_t nmemb, void* userp) {\n    size_t realsize = size * nmemb;\n    MemoryStruct* mem = (MemoryStruct*)userp;\n\n    char* ptr = realloc(mem->data, mem->size + realsize + 1);\n    if(!ptr) return 0;\n\n    mem->data = ptr;\n    memcpy(&(mem->data[mem->size]), contents, realsize);\n    mem->size += realsize;\n    mem->data[mem->size] = 0;\n\n    return realsize;\n}\n\nint main(void) {\n    CURL* curl;\n    CURLcode res;\n    MemoryStruct chunk = {NULL, 0};\n\n    curl_global_init(CURL_GLOBAL_ALL);\n    curl = curl_easy_init();\n\n    if(curl) {\n        struct curl_slist* headers = NULL;\n        headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n        const char* url = \"https://api.typecast.ai/v2/voices/tc_60e5426de8b95f1d3000d7b5\";\n\n        curl_easy_setopt(curl, CURLOPT_URL, url);\n        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);\n        curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*)&chunk);\n\n        res = curl_easy_perform(curl);\n\n        if(res == CURLE_OK) {\n            printf(\"%s\\n\", chunk.data);\n        }\n\n        curl_slist_free_all(headers);\n        curl_easy_cleanup(curl);\n        free(chunk.data);\n    }\n\n    curl_global_cleanup();\n    return 0;\n}\n"},{"lang":"Swift","label":"Swift (URLSession)","source":"import Foundation\n\nlet voiceId = \"tc_60e5426de8b95f1d3000d7b5\"\nlet url = URL(string: \"https://api.typecast.ai/v2/voices/\\(voiceId)\")!\nvar request = URLRequest(url: url)\nrequest.httpMethod = \"GET\"\nrequest.setValue(\"<api-key>\", forHTTPHeaderField: \"X-API-KEY\")\n\nlet task = URLSession.shared.dataTask(with: request) { data, response, error in\n    if let data = data, let jsonString = String(data: data, encoding: .utf8) {\n        print(jsonString)\n    }\n}\ntask.resume()\n"},{"lang":"Rust","label":"Rust (reqwest)","source":"use reqwest;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let client = reqwest::Client::new();\n    let voice_id = \"tc_60e5426de8b95f1d3000d7b5\";\n\n    let url = format!(\"https://api.typecast.ai/v2/voices/{}\", voice_id);\n\n    let response = client\n        .get(&url)\n        .header(\"X-API-KEY\", \"<api-key>\")\n        .send()\n        .await?;\n\n    if response.status().is_success() {\n        let body = response.text().await?;\n        println!(\"{}\", body);\n    }\n\n    Ok(())\n}\n"}]}},"/v3/voices/{voice_id}":{"get":{"tags":["Voices"],"x-mint":{"href":"/api-reference/voices/get-voice-details"},"summary":"Get Voice Details","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceV3"},"example":{"age":"young_adult","gender":"female","models":[{"version":"ssfm-v30","emotions":["normal","happy","sad","angry"]}],"voice_id":"tc_6045d56d5f9ae03ac175cf73","use_cases":["Game","Anime"],"voice_name":{"eng":"Valkyrie","kor":"발키리"},"voice_type":"original","preview_url":"https://static2.typecast.ai/data/actor/valkyrie.mp3"}}},"description":"Voice retrieved successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Invalid voice ID","error_code":"INVALID_VOICE_ID"}}},"description":"The voice ID format is invalid"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Voice not found","error_code":"VOICE_NOT_FOUND"}}},"description":"The voice does not exist or is not available to this account"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid voice ID"}},"parameters":[{"in":"path","name":"voice_id","schema":{"type":"string","title":"Voice Id"},"required":true,"description":"Unique voice identifier."}],"description":"Returns one accessible built-in or completed custom voice with localized names, supported models and emotions, recommended use cases, and a preview URL when available. Built-in voice IDs use the `tc_` prefix; custom voice IDs use `uc_`.","operationId":"get_voice_v3_v3_voices__voice_id__get","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request GET \\\n  --url https://api.typecast.ai/v3/voices/tc_6045d56d5f9ae03ac175cf73 \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nresponse = requests.get(\n    \"https://api.typecast.ai/v3/voices/tc_6045d56d5f9ae03ac175cf73\",\n    headers={\"X-API-KEY\": \"<api-key>\"},\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"}]}},"/v1/text-to-speech/stream":{"post":{"tags":["Text-to-Speech"],"x-mint":{"href":"/api-reference/text-to-speech/streaming-text-to-speech"},"summary":"Streaming Text To Speech","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"content":{"audio/wav":{"schema":{"type":"string","format":"binary","description":"Chunked WAV audio stream (16-bit, mono, 32000 Hz). First chunk includes WAV header with size 0xFFFFFFFF (indicating streaming), followed by raw PCM data. Subsequent chunks contain only PCM data."},"example":"[Binary audio stream - WAV chunks]"}},"description":"Success - Returns streaming audio data in chunks"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid voice_id"}}},"description":"Bad Request - Invalid parameters"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Authentication failed"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Insufficient credit"}}},"description":"Payment Required - Insufficient credits"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Voice not found"}}},"description":"Not Found - Voice model not available"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text.","error_code":"TEXT_NOT_SYNTHESIZABLE"}}},"description":"Validation Error - The request is invalid or the input text cannot be synthesized.\r\nInput errors detected before streaming starts return `TEXT_NOT_SYNTHESIZABLE`. After the streaming response has started, its HTTP status can no longer be changed."},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Too many requests"}}},"description":"Too Many Requests - Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"An unexpected error occurred"}}},"description":"Internal Server Error - Server processing failed"}},"deprecated":false,"description":"Generate speech from text using real-time streaming, allowing audio playback to begin before the entire synthesis is complete.\n\nThis endpoint streams audio data in chunks, enabling low-latency audio playback for applications requiring immediate feedback.\n\n**Streaming Format:**\n\n* **WAV format**: First chunk contains WAV header (size\\=0xFFFFFFFF for streaming) followed by raw PCM data. Subsequent chunks contain only PCM data.\n* **MP3 format**: Each chunk contains post-processed MP3 data that can be decoded independently.\n\n**Use Cases:**\n\n* Conversational AI, chatbots and real-time voice assistants\n* Interactive applications requiring immediate audio feedback\n* Long-form content where waiting for full synthesis is impractical\n\n**Request Parameters:**\nUses the same TTSRequest schema as the standard TTS endpoint. Set `output.audio_format` to \"wav\" or \"mp3\" to control the streaming format.","operationId":"text_to_speech_stream_v1_text_to_speech_stream_post","requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"TTSRequestStreamStream","required":["voice_id","text","model"],"properties":{"text":{"type":"string","title":"Text","example":"Everything is so incredibly perfect that I feel like I'm dreaming.","maxLength":2000,"minLength":1,"description":"Text to convert to speech. Minimum 1 character, maximum 2000 characters. Credits consumed based on text length. Supports multiple languages including English, Korean, Japanese, and Chinese. Special characters and punctuation are handled automatically."},"model":{"$ref":"#/components/schemas/TTSModel","example":"ssfm-v30","description":"Voice model to use for speech synthesis.\r\n\r\n* **ssfm-v30**: Latest model with improved prosody and additional emotion presets (recommended)\r\n* **ssfm-v21**: Stable production model with reliable quality"},"output":{"type":"object","title":"","properties":{"audio_pitch":{"type":"integer","title":"Audio Pitch","default":0,"example":0,"maximum":12,"minimum":-12,"description":"Adjusts the pitch in semitones to affect perceived gender and age: -12 (one octave lower, deeper voice), -6 (half octave lower), 0 (original pitch, default), +6 (half octave higher), +12 (one octave higher, higher voice)"},"audio_tempo":{"type":"number","title":"Audio Tempo","default":1,"example":1,"maximum":2,"minimum":0.5,"description":"Controls speech speed: 0.5 (half speed, very slow and clear), 0.75 (slightly slower than normal), 1.0 (normal speaking speed, default), 1.5 (50% faster than normal), 2.0 (double speed, very fast speech)"},"target_lufs":{"anyOf":[{"type":"number","maximum":0,"minimum":-70},{"type":"null"}],"title":"Target Lufs","example":-14,"description":"Sets the target absolute loudness (LUFS) for streaming output audio. This normalizes generated audio to a consistent loudness regardless of the original source. Cannot be used with the `volume` parameter.\r\n\r\nRecommended values: -14 (common streaming standard), -23 (broadcast standard).\r\n"},"audio_format":{"enum":["wav","mp3"],"type":"string","title":"Audio Format","default":"wav","example":"wav","description":"Output audio format for streaming.\r\n\r\n**WAV format:**\r\n- Uncompressed PCM audio\r\n- 16-bit depth, mono channel, **32000 Hz** sample rate\r\n- Chunked transfer: first chunk contains the WAV header (size = 0xFFFFFFFF), subsequent chunks contain raw PCM data\r\n- Recommended when you want to play audio as it arrives\r\n\r\n**MP3 format:**\r\n- Compressed MPEG Layer III audio\r\n- 320 kbps bitrate, 44100 Hz sample rate\r\n- Chunked transfer: each chunk contains independently decodable MPEG frames\r\n- Recommended for bandwidth-constrained clients\r\n"},"remove_silence_ms":{"anyOf":[{"type":"integer","maximum":1000,"minimum":0},{"type":"null"}],"title":"Remove Silence Ms","default":null,"example":100,"description":"When enabled, shortens detected silences longer than the specified duration to that duration. The value is in milliseconds (ms). The value is the duration of silence to retain, not the amount to remove.\r\n\r\n**Accepted values:**\r\n\r\n- An integer from **0 to 1000**, with a recommended range of 0 to 200.\r\n- Omitted or `null`: silence removal is disabled.\r\n- `0`: removes detected silence longer than 0 ms. **This does not disable the feature.**\r\n- Booleans, strings, fractional values, and out-of-range values are invalid.\r\n\r\n**Example:** `100` shortens detected silences longer than 100 ms to 100 ms. Lower values include shorter silence segments for removal and leave less silence in each affected segment."}},"description":"Streaming audio output settings including pitch (-12 to +12 semitones), tempo (0.5x to 2.0x), format (wav/mp3), and target\\_lufs (-70 to 0 LUFS). Note: volume is not available in streaming mode.\r\n\r\nAlso supports `remove_silence_ms` (integer, 0–1000 ms) for silence removal."},"prompt":{"oneOf":[{"$ref":"#/components/schemas/SmartPrompt"},{"$ref":"#/components/schemas/PresetPrompt"},{"$ref":"#/components/schemas/Prompt"}],"title":"Prompt","description":"Emotion and style settings for the generated speech, including emotion type (happy/sad/angry/normal) and intensity (0.0 to 2.0) to control the emotional expression"},"language":{"type":"string","title":"Language","example":"eng","description":"Language code following ISO 639-3 standard. Case-insensitive (both \"ENG\" and \"eng\" are accepted). If not provided, will be auto-detected based on text content.\r\n\r\n<details>\r\n  <summary><strong>ssfm-v30 Supported Languages (37)</strong></summary>\r\n\r\n  | Code | Language  | Code | Language   | Code | Language   |\r\n  | ---- | --------- | ---- | ---------- | ---- | ---------- |\r\n  | ARA  | Arabic    | IND  | Indonesian | POR  | Portuguese |\r\n  | BEN  | Bengali   | ITA  | Italian    | RON  | Romanian   |\r\n  | BUL  | Bulgarian | JPN  | Japanese   | RUS  | Russian    |\r\n  | CES  | Czech     | KOR  | Korean     | SLK  | Slovak     |\r\n  | DAN  | Danish    | MSA  | Malay      | SPA  | Spanish    |\r\n  | DEU  | German    | NAN  | Min Nan    | SWE  | Swedish    |\r\n  | ELL  | Greek     | NLD  | Dutch      | TAM  | Tamil      |\r\n  | ENG  | English   | NOR  | Norwegian  | TGL  | Tagalog    |\r\n  | FIN  | Finnish   | PAN  | Punjabi    | THA  | Thai       |\r\n  | FRA  | French    | POL  | Polish     | TUR  | Turkish    |\r\n  | HIN  | Hindi     | UKR  | Ukrainian  | VIE  | Vietnamese |\r\n  | HRV  | Croatian  | YUE  | Cantonese  | ZHO  | Chinese    |\r\n  | HUN  | Hungarian |      |            |      |            |\r\n</details>\r\n\r\n<details>\r\n  <summary><strong>ssfm-v21 Supported Languages (27)</strong></summary>\r\n\r\n  | Code | Language  | Code | Language   | Code | Language  |\r\n  | ---- | --------- | ---- | ---------- | ---- | --------- |\r\n  | ARA  | Arabic    | IND  | Indonesian | RON  | Romanian  |\r\n  | BUL  | Bulgarian | ITA  | Italian    | RUS  | Russian   |\r\n  | CES  | Czech     | JPN  | Japanese   | SLK  | Slovak    |\r\n  | DAN  | Danish    | KOR  | Korean     | SPA  | Spanish   |\r\n  | DEU  | German    | MSA  | Malay      | SWE  | Swedish   |\r\n  | ELL  | Greek     | NLD  | Dutch      | TAM  | Tamil     |\r\n  | ENG  | English   | POL  | Polish     | TGL  | Tagalog   |\r\n  | FIN  | Finnish   | POR  | Portuguese | UKR  | Ukrainian |\r\n  | FRA  | French    | HRV  | Croatian   | ZHO  | Chinese   |\r\n</details>"},"voice_id":{"type":"string","title":"Voice Id","example":"tc_60e5426de8b95f1d3000d7b5","description":"Voice identifier. Two prefixes are supported:\r\n\r\n* `tc_` — Built-in Typecast voices (e.g., `tc_60e5426de8b95f1d3000d7b5`). See [Listing all voices](/docs/api-reference/voices/list-voices) for available IDs.\r\n* `uc_` — Custom voices created via [Instant cloning](/docs/api-reference/voices/instant-cloning) (e.g., `uc_64a1b2c3d4e5f6a7b8c9d0e1`). Only the owner of a cloned voice can use it.\r\n\r\nCase-sensitive: must use lowercase prefix."}},"description":"Text-to-speech streaming request parameters"}}},"required":true,"description":""},"x-codeSamples":[{"lang":"cURL","label":"cURL (stream + play)","source":"# Pipe streaming audio directly into ffplay for real-time playback.\n# Requires: ffmpeg (brew/choco/apt install ffmpeg)\ncurl -N -s --request POST \\\n  --url https://api.typecast.ai/v1/text-to-speech/stream \\\n  --header 'Content-Type: application/json' \\\n  --header 'X-API-KEY: <api-key>' \\\n  --data @- <<EOF | ffplay -autoexit -nodisp -loglevel error -i pipe:0\n{\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n  \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n  \"model\": \"ssfm-v30\"\n}\nEOF\n"},{"lang":"Python","label":"Python (requests + sounddevice)","source":"# Real-time playback using sounddevice (pip install requests sounddevice).\n# Streaming WAV format: 32000 Hz, 16-bit, mono — skip the 44-byte\n# WAV header and feed raw PCM samples to the audio output.\nimport requests\nimport sounddevice as sd\n\nAPI_HOST = \"https://api.typecast.ai\"\nheaders = {\"X-API-KEY\": \"<api-key>\", \"Content-Type\": \"application/json\"}\npayload = {\n    \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n    \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n    \"model\": \"ssfm-v30\"\n}\n\nresp = requests.post(\n    f\"{API_HOST}/v1/text-to-speech/stream\",\n    headers=headers, json=payload, stream=True, timeout=60,\n)\nresp.raise_for_status()\n\nwith sd.RawOutputStream(samplerate=32000, channels=1, dtype=\"int16\") as player:\n    buf, first = bytearray(), True\n    for chunk in resp.iter_content(chunk_size=4096):\n        if not chunk:\n            continue\n        if first:\n            chunk = chunk[44:]  # strip WAV header\n            first = False\n        buf.extend(chunk)\n        # Write 2-byte-aligned slices (int16 samples).\n        n = len(buf) - (len(buf) % 2)\n        if n:\n            player.write(bytes(buf[:n]))\n            del buf[:n]\n\nprint(\"Playback completed\")\n"},{"lang":"C#","label":"C# (HttpClient + ffplay)","source":"// Real-time playback by piping the stream into ffplay.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\nusing System;\nusing System.Diagnostics;\nusing System.Net.Http;\nusing System.Text;\nusing System.Threading.Tasks;\n\nvar client = new HttpClient();\nclient.DefaultRequestHeaders.Add(\"X-API-KEY\", \"<api-key>\");\n\nvar requestBody = @\"{\n  \"\"voice_id\"\": \"\"tc_60e5426de8b95f1d3000d7b5\"\",\n  \"\"text\"\": \"\"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\"\",\n  \"\"model\"\": \"\"ssfm-v30\"\"\n}\";\n\nvar ffplay = new Process\n{\n    StartInfo = new ProcessStartInfo\n    {\n        FileName = \"ffplay\",\n        Arguments = \"-autoexit -nodisp -loglevel error -i pipe:0\",\n        RedirectStandardInput = true,\n        UseShellExecute = false\n    }\n};\nffplay.Start();\n\nvar request = new HttpRequestMessage(HttpMethod.Post, \"https://api.typecast.ai/v1/text-to-speech/stream\")\n{\n    Content = new StringContent(requestBody, Encoding.UTF8, \"application/json\")\n};\n\n// ResponseHeadersRead enables true streaming (avoids full buffering).\nusing var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);\nresponse.EnsureSuccessStatusCode();\nusing var stream = await response.Content.ReadAsStreamAsync();\nawait stream.CopyToAsync(ffplay.StandardInput.BaseStream);\nffplay.StandardInput.Close();\nawait ffplay.WaitForExitAsync();\n"},{"lang":"Kotlin","label":"Kotlin (OkHttp + ffplay)","source":"// Real-time playback by piping the OkHttp response stream into ffplay.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\n// For Android, replace the ffplay Process with AudioTrack + raw PCM feed.\nimport okhttp3.MediaType.Companion.toMediaType\nimport okhttp3.OkHttpClient\nimport okhttp3.Request\nimport okhttp3.RequestBody.Companion.toRequestBody\n\nval ffplay = ProcessBuilder(\n    \"ffplay\", \"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\"\n).redirectError(ProcessBuilder.Redirect.DISCARD).start()\n\nval client = OkHttpClient()\nval body = \"\"\"\n{\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n  \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n  \"model\": \"ssfm-v30\"\n}\n\"\"\".trimIndent().toRequestBody(\"application/json\".toMediaType())\n\nval request = Request.Builder()\n    .url(\"https://api.typecast.ai/v1/text-to-speech/stream\")\n    .addHeader(\"X-API-KEY\", \"<api-key>\")\n    .post(body)\n    .build()\n\nclient.newCall(request).execute().use { response ->\n    response.body?.byteStream()?.use { input -> input.copyTo(ffplay.outputStream) }\n}\nffplay.outputStream.close()\nffplay.waitFor()\n"},{"lang":"C++","label":"C++ (libcurl + ffplay)","source":"// Real-time playback: libcurl write callback pipes each chunk into\n// ffplay via popen. Requires: ffmpeg (brew/choco/apt install ffmpeg)\n#include <curl/curl.h>\n#include <cstdio>\n#include <string>\n\nstatic FILE* player = nullptr;\n\nsize_t cb(void* ptr, size_t size, size_t nmemb, void*) {\n    return fwrite(ptr, size, nmemb, player);\n}\n\nint main() {\n    player = popen(\"ffplay -autoexit -nodisp -loglevel error -i pipe:0\", \"w\");\n\n    CURL* curl = curl_easy_init();\n    struct curl_slist* headers = nullptr;\n    headers = curl_slist_append(headers, \"Content-Type: application/json\");\n    headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n    std::string body = R\"({\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n        \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n        \"model\": \"ssfm-v30\"\n    })\";\n\n    curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v1/text-to-speech/stream\");\n    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb);\n\n    curl_easy_perform(curl);\n\n    curl_slist_free_all(headers);\n    curl_easy_cleanup(curl);\n    pclose(player);\n    return 0;\n}\n"},{"lang":"C","label":"C (libcurl + ffplay)","source":"/* Real-time playback: libcurl write callback pipes each chunk into\n * ffplay via popen. Requires: ffmpeg (brew/choco/apt install ffmpeg) */\n#include <stdio.h>\n#include <curl/curl.h>\n\nstatic FILE* player = NULL;\n\nsize_t cb(void* ptr, size_t size, size_t nmemb, void* ud) {\n    (void)ud;\n    return fwrite(ptr, size, nmemb, player);\n}\n\nint main(void) {\n    player = popen(\"ffplay -autoexit -nodisp -loglevel error -i pipe:0\", \"w\");\n\n    curl_global_init(CURL_GLOBAL_ALL);\n    CURL* curl = curl_easy_init();\n\n    struct curl_slist* headers = NULL;\n    headers = curl_slist_append(headers, \"Content-Type: application/json\");\n    headers = curl_slist_append(headers, \"X-API-KEY: <api-key>\");\n\n    const char* body =\n        \"{\"\n        \"\\\"voice_id\\\":\\\"tc_60e5426de8b95f1d3000d7b5\\\",\"\n        \"\\\"text\\\":\\\"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\\\",\"\n        \"\\\"model\\\":\\\"ssfm-v30\\\"\"\n        \"}\";\n\n    curl_easy_setopt(curl, CURLOPT_URL, \"https://api.typecast.ai/v1/text-to-speech/stream\");\n    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);\n    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb);\n\n    curl_easy_perform(curl);\n\n    curl_slist_free_all(headers);\n    curl_easy_cleanup(curl);\n    curl_global_cleanup();\n    pclose(player);\n    return 0;\n}\n"},{"lang":"Swift","label":"Swift (URLSession + ffplay)","source":"// Real-time playback (macOS): pipe URLSession bytes into ffplay via\n// Process. Requires: ffmpeg (brew install ffmpeg).\n// Requires iOS 15 / macOS 12 for URLSession.bytes(for:).\n// Compile with: swiftc -parse-as-library main.swift -o streaming_tts\n// For iOS, replace Process/ffplay with AVAudioEngine + scheduled PCM buffers.\nimport Foundation\n\n@main\nstruct StreamingTTS {\n    static func main() async throws {\n        let ffplay = Process()\n        ffplay.executableURL = URL(fileURLWithPath: \"/usr/bin/env\")\n        ffplay.arguments = [\"ffplay\", \"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\"]\n        let pipe = Pipe()\n        ffplay.standardInput = pipe\n        try ffplay.run()\n\n        var request = URLRequest(url: URL(string: \"https://api.typecast.ai/v1/text-to-speech/stream\")!)\n        request.httpMethod = \"POST\"\n        request.setValue(\"application/json\", forHTTPHeaderField: \"Content-Type\")\n        request.setValue(\"<api-key>\", forHTTPHeaderField: \"X-API-KEY\")\n        request.httpBody = try JSONSerialization.data(withJSONObject: [\n            \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n            \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n            \"model\": \"ssfm-v30\"\n        ])\n\n        let (bytes, _) = try await URLSession.shared.bytes(for: request)\n        var buffer = Data()\n        buffer.reserveCapacity(4096)\n        for try await byte in bytes {\n            buffer.append(byte)\n            if buffer.count >= 4096 {\n                try pipe.fileHandleForWriting.write(contentsOf: buffer)\n                buffer.removeAll(keepingCapacity: true)\n            }\n        }\n        if !buffer.isEmpty {\n            try pipe.fileHandleForWriting.write(contentsOf: buffer)\n        }\n        try pipe.fileHandleForWriting.close()\n        ffplay.waitUntilExit()\n    }\n}\n"},{"lang":"Rust","label":"Rust (reqwest + ffplay)","source":"// Real-time playback: pipe reqwest stream into ffplay via tokio Command.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\n// Cargo.toml:\n//   reqwest = { version = \"0.12\", features = [\"json\", \"stream\"] }\n//   tokio   = { version = \"1\", features = [\"full\"] }\n//   serde_json = \"1\"\nuse reqwest;\nuse serde_json::json;\nuse std::process::Stdio;\nuse tokio::io::AsyncWriteExt;\nuse tokio::process::Command;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n    let mut ffplay = Command::new(\"ffplay\")\n        .args([\"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\"])\n        .stdin(Stdio::piped())\n        .spawn()?;\n    let mut stdin = ffplay.stdin.take().expect(\"failed to open ffplay stdin\");\n\n    let client = reqwest::Client::new();\n    let body = json!({\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n        \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n        \"model\": \"ssfm-v30\"\n    });\n\n    let mut response = client\n        .post(\"https://api.typecast.ai/v1/text-to-speech/stream\")\n        .header(\"X-API-KEY\", \"<api-key>\")\n        .header(\"Content-Type\", \"application/json\")\n        .json(&body)\n        .send()\n        .await?;\n\n    while let Some(chunk) = response.chunk().await? {\n        stdin.write_all(&chunk).await?;\n    }\n    drop(stdin);\n    ffplay.wait().await?;\n    Ok(())\n}\n"},{"lang":"JavaScript","label":"JavaScript (Node.js + ffplay)","source":"// Node 18+ (built-in fetch). Pipe streamed audio into ffplay.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\nimport { spawn } from \"node:child_process\";\n\nconst ffplay = spawn(\n    \"ffplay\",\n    [\"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\"],\n    { stdio: [\"pipe\", \"ignore\", \"ignore\"] },\n);\n\nconst response = await fetch(\"https://api.typecast.ai/v1/text-to-speech/stream\", {\n    method: \"POST\",\n    headers: {\n        \"Content-Type\": \"application/json\",\n        \"X-API-KEY\": \"<api-key>\"\n    },\n    body: JSON.stringify({\n        voice_id: \"tc_60e5426de8b95f1d3000d7b5\",\n        text: \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n        model: \"ssfm-v30\"\n    })\n});\nif (!response.ok) throw new Error(`HTTP ${response.status}`);\n\n// fetch().body is a Web ReadableStream — read chunks as they arrive.\nconst reader = response.body.getReader();\nwhile (true) {\n    const { value, done } = await reader.read();\n    if (done) break;\n    ffplay.stdin.write(value);\n}\nffplay.stdin.end();\nawait new Promise((resolve) => ffplay.on(\"close\", resolve));\n"},{"lang":"PHP","label":"PHP (curl + ffplay)","source":"<?php\n// Pipes the libcurl write callback straight into ffplay's stdin.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\n$ffplay = popen(\"ffplay -autoexit -nodisp -loglevel error -i pipe:0\", \"w\");\n\n$payload = json_encode([\n    \"voice_id\" => \"tc_60e5426de8b95f1d3000d7b5\",\n    \"text\" => \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n    \"model\" => \"ssfm-v30\"\n]);\n\n$ch = curl_init(\"https://api.typecast.ai/v1/text-to-speech/stream\");\ncurl_setopt_array($ch, [\n    CURLOPT_POST => true,\n    CURLOPT_HTTPHEADER => [\n        \"Content-Type: application/json\",\n        \"X-API-KEY: <api-key>\"\n    ],\n    CURLOPT_POSTFIELDS => $payload,\n    CURLOPT_WRITEFUNCTION => function ($ch, $data) use ($ffplay) {\n        fwrite($ffplay, $data);\n        return strlen($data);\n    }\n]);\ncurl_exec($ch);\npclose($ffplay);\n"},{"lang":"Go","label":"Go (net/http + ffplay)","source":"// Pipes the streaming response body into ffplay's stdin.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\npackage main\n\nimport (\n    \"bytes\"\n    \"io\"\n    \"net/http\"\n    \"os/exec\"\n)\n\nfunc main() {\n    ffplay := exec.Command(\"ffplay\", \"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\")\n    stdin, _ := ffplay.StdinPipe()\n    if err := ffplay.Start(); err != nil {\n        panic(err)\n    }\n\n    body := []byte(`{\n        \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n        \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n        \"model\": \"ssfm-v30\"\n    }`)\n\n    req, _ := http.NewRequest(\"POST\", \"https://api.typecast.ai/v1/text-to-speech/stream\", bytes.NewReader(body))\n    req.Header.Set(\"Content-Type\", \"application/json\")\n    req.Header.Set(\"X-API-KEY\", \"<api-key>\")\n\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        panic(err)\n    }\n    defer resp.Body.Close()\n\n    io.Copy(stdin, resp.Body)\n    stdin.Close()\n    ffplay.Wait()\n}\n"},{"lang":"Java","label":"Java (HttpClient + ffplay)","source":"// Java 11+ HttpClient with InputStream body handler.\n// Pipes the streaming response into ffplay's stdin.\n// Requires: ffmpeg (brew/choco/apt install ffmpeg)\nimport java.net.URI;\nimport java.net.http.HttpClient;\nimport java.net.http.HttpRequest;\nimport java.net.http.HttpResponse;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\npublic class StreamingTTS {\n    public static void main(String[] args) throws Exception {\n        Process ffplay = new ProcessBuilder(\n                \"ffplay\", \"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\")\n                .redirectError(ProcessBuilder.Redirect.DISCARD)\n                .start();\n\n        String body = \"\"\"\n            {\n              \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\n              \"text\": \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n              \"model\": \"ssfm-v30\"\n            }\n            \"\"\";\n\n        HttpRequest request = HttpRequest.newBuilder()\n                .uri(URI.create(\"https://api.typecast.ai/v1/text-to-speech/stream\"))\n                .header(\"Content-Type\", \"application/json\")\n                .header(\"X-API-KEY\", \"<api-key>\")\n                .POST(HttpRequest.BodyPublishers.ofString(body))\n                .build();\n\n        HttpResponse<InputStream> response = HttpClient.newHttpClient()\n                .send(request, HttpResponse.BodyHandlers.ofInputStream());\n\n        try (InputStream in = response.body();\n             OutputStream out = ffplay.getOutputStream()) {\n            in.transferTo(out);\n        }\n        ffplay.waitFor();\n    }\n}\n"},{"lang":"Ruby","label":"Ruby (net/http + ffplay)","source":"# Pipes the streaming response into ffplay via IO.popen.\n# Requires: ffmpeg (brew/choco/apt install ffmpeg)\nrequire \"net/http\"\nrequire \"uri\"\nrequire \"json\"\n\nffplay = IO.popen(\n  [\"ffplay\", \"-autoexit\", \"-nodisp\", \"-loglevel\", \"error\", \"-i\", \"pipe:0\"],\n  \"wb\",\n)\n\nuri = URI(\"https://api.typecast.ai/v1/text-to-speech/stream\")\nhttp = Net::HTTP.new(uri.host, uri.port)\nhttp.use_ssl = true\n\nreq = Net::HTTP::Post.new(uri)\nreq[\"Content-Type\"] = \"application/json\"\nreq[\"X-API-KEY\"] = \"<api-key>\"\nreq.body = {\n  voice_id: \"tc_60e5426de8b95f1d3000d7b5\",\n  text: \"Thanks for reaching out. Your reservation has been confirmed for Friday at 7 PM.\",\n  model: \"ssfm-v30\"\n}.to_json\n\nhttp.request(req) do |response|\n  response.read_body { |chunk| ffplay.write(chunk) }\nend\n\nffplay.close\n"},{"lang":"cURL","label":"Silence removal","source":"curl --no-buffer --request POST 'https://api.typecast.ai/v1/text-to-speech/stream' \\\n  --header 'X-API-KEY: <api-key>' \\\n  --header 'Content-Type: application/json' \\\n  --output review.wav \\\n  --data-binary @- <<'JSON'\n{\n  \"voice_id\": \"<voice-id>\",\n  \"text\": \"Hello. Thank you for listening.\",\n  \"model\": \"ssfm-v30\",\n  \"output\": {\n    \"audio_format\": \"wav\",\n    \"remove_silence_ms\": 300\n  }\n}\nJSON\n"}]}},"/v1/users/me/subscription":{"get":{"tags":["Subscription"],"x-mint":{"href":"/api-reference/subscription/get-subscription"},"summary":"Get Subscription","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionResponse"},"example":{"plan":"lite","limits":{"concurrency_limit":5,"custom_voice_slot":10},"credits":{"plan_credits":200000,"used_credits":157300}}}},"description":"Successful Response"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Authentication failed"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Too many requests"}}},"description":"Too Many Requests - Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"An unexpected error occurred"}}},"description":"Internal Server Error"}},"description":"Retrieve the authenticated user's current subscription information, including plan name, credit usage, concurrency limit, and custom voice slot capacity.\n\nUse this endpoint to check remaining credits, verify your current plan, or see how many custom voice slots are available before cloning a new voice with `POST /v1/voices/clone`. The `limits.custom_voice_slot` value is the maximum number of custom voices the current plan can hold at once; free the slot by calling `DELETE /v1/voices/{voice_id}`.","operationId":"get_my_subscription_v1_users_me_subscription_get"}},"/v1/text-to-speech/compose":{"post":{"tags":["Text-to-Speech"],"x-mint":{"href":"/api-reference/text-to-speech/compose-text-to-speech"},"summary":"Compose Text To Speech","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"content":{"audio/wav":{"schema":{"type":"string","format":"binary"},"example":"[Binary audio data - WAV file content]"}},"description":"Binary composed audio. The media type matches the requested `audio_format`."},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Authentication failed"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Insufficient credit"}}},"description":"Insufficient credits for the combined text length"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text.","error_code":"TEXT_NOT_SYNTHESIZABLE"}}},"description":"Invalid segments, compose limits exceeded, or input text cannot be synthesized"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"An unexpected error occurred"}}},"description":"Unexpected server error while synthesizing one or more segments"}},"deprecated":false,"description":"Generate multiple speech segments and pauses as one audio file. Add `tts` and `pause` objects to `segments` in the order they should appear. Each `tts` segment accepts the same voice, model, prompt, and output settings as `POST /v1/text-to-speech`; voices and models may differ between segments.\n\n**Limits**\n- Up to 50 total segments, with at least one `tts` segment\n- Up to 2,000 characters across all `tts` segments\n- Up to 10 seconds per pause and 60 seconds across all pauses\n- All `tts` segments must use the same `audio_format`\n\nCredits are charged only for the combined text length; pauses are free. Segments are synthesized in parallel and returned in input order. If any segment fails, the entire request fails and no credits are charged.\n\n**Response**\nA successful request returns the composed audio directly as binary data, not JSON. The response `Content-Type` is `audio/wav` or `audio/mpeg`, based on the `audio_format` requested by the segments.","operationId":"text_to_speech_compose_v1_text_to_speech_compose_post","requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"ComposeRequest","required":["segments"],"properties":{"segments":{"type":"array","items":{"oneOf":[{"type":"object","title":"TTSComposeSegment","examples":[{"text":"Welcome to today's update.","type":"tts","model":"ssfm-v30","output":{"audio_format":"wav"},"language":"eng","voice_id":"tc_672c5f5ce59fac2a48faeaee"}],"required":["type","voice_id","text","model"],"properties":{"text":{"type":"string","title":"Text","example":"Welcome to today's update.","maxLength":2000,"minLength":1,"description":"Text to synthesize. The combined text across all `tts` segments may not exceed 2,000 characters."},"type":{"type":"string","const":"tts","title":"Type","default":"tts","description":"Segment discriminator. Always `tts`."},"model":{"$ref":"#/components/schemas/TTSModel","example":"ssfm-v30","description":"Voice model used for this segment. Models may differ between segments."},"output":{"type":"object","title":"Output","properties":{"volume":{"anyOf":[{"type":"integer","maximum":200,"minimum":0},{"type":"null"}],"title":"Volume","example":100,"description":"Adjusts the relative volume of the output audio: 0 (completely silent), 50 (half volume), 100 (standard volume, default), 150 (50% louder than standard), 200 (maximum volume, twice as loud as standard).\r\n\r\nSince this only scales the existing volume, using `volume` can amplify the loudness differences between voices if they have different baseline levels. For consistent output across all clips, use `target_lufs` instead.\r\n\r\n- **Note:** This parameter cannot be used simultaneously with the `target_lufs` parameter.\r\n\r\nRequired range: 0 <= x <= 200\r\n"},"audio_pitch":{"type":"integer","title":"Audio Pitch","default":0,"example":0,"maximum":12,"minimum":-12,"description":"Adjusts the pitch in semitones to affect perceived gender and age: -12 (one octave lower, deeper voice), -6 (half octave lower), 0 (original pitch, default), +6 (half octave higher), +12 (one octave higher, higher voice)"},"audio_tempo":{"type":"number","title":"Audio Tempo","default":1,"example":1,"maximum":2,"minimum":0.5,"description":"Controls speech speed: 0.5 (half speed, very slow and clear), 0.75 (slightly slower than normal), 1.0 (normal speaking speed, default), 1.5 (50% faster than normal), 2.0 (double speed, very fast speech)"},"target_lufs":{"anyOf":[{"type":"number","maximum":0,"minimum":-70},{"type":"null"}],"title":"Target Lufs","example":-14,"description":"Sets the target absolute loudness (LUFS) for the output audio. This normalizes all generated voices to a consistent volume level, regardless of the original source's loudness. Values closer to 0 are louder, while values closer to -70 are quieter.\r\n\r\n- Required range: -70 <= x <= 0\r\n- Recommended values: -14 (common streaming standard), -23 (broadcast standard)\r\n- **Note:** This parameter cannot be used simultaneously with the `volume` parameter. Use `target_lufs` for consistent absolute loudness across different clips, or use `volume` for traditional relative scaling.\r\n"},"audio_format":{"enum":["wav","mp3"],"type":"string","title":"Audio Format","default":"wav","example":"wav","description":"Output audio format.\r\n\r\n**WAV format:**\r\n- Uncompressed PCM audio\r\n- 16-bit depth, mono channel, 44100 Hz sample rate\r\n- Higher quality, larger file size\r\n- Recommended for professional audio production\r\n\r\n**MP3 format:**\r\n- Compressed MPEG Layer III audio\r\n- 320 kbps bitrate, 44100 Hz sample rate\r\n- Smaller file size\r\n- Recommended for web streaming and distribution\r\n"},"remove_silence_ms":{"anyOf":[{"type":"integer","maximum":1000,"minimum":0},{"type":"null"}],"title":"Remove Silence Ms","default":null,"example":100,"description":"When enabled, shortens detected silences longer than the specified duration to that duration. The value is in milliseconds (ms). The value is the duration of silence to retain, not the amount to remove.\r\n\r\n**Accepted values:**\r\n\r\n- An integer from **0 to 1000**, with a recommended range of 0 to 200.\r\n- Omitted or `null`: silence removal is disabled.\r\n- `0`: removes detected silence longer than 0 ms. **This does not disable the feature.**\r\n- Booleans, strings, fractional values, and out-of-range values are invalid.\r\n\r\n**Example:** `100` shortens detected silences longer than 100 ms to 100 ms. Lower values include shorter silence segments for removal and leave less silence in each affected segment."}},"description":"Audio settings for this segment. All segments must use the same `audio_format`.\r\n\r\nUse `remove_silence_ms` (integer, 0–1000 ms) to shorten detected silence."},"prompt":{"oneOf":[{"$ref":"#/components/schemas/SmartPrompt"},{"$ref":"#/components/schemas/PresetPrompt"},{"$ref":"#/components/schemas/Prompt"}],"title":"Prompt","description":"Emotion and context settings for this segment."},"language":{"type":"string","title":"Language","example":"eng","description":"ISO 639-3 language code. If omitted, the language is detected from the text."},"voice_id":{"type":"string","title":"Voice Id","example":"tc_672c5f5ce59fac2a48faeaee","description":"Built-in (`tc_`) or custom (`uc_`) Typecast voice identifier."}},"description":"A speech segment with the same synthesis options as a standard text-to-speech request."},{"$ref":"#/components/schemas/PauseComposeSegment"}],"discriminator":{"mapping":{"tts":"#/components/schemas/TTSComposeSegment","pause":"#/components/schemas/PauseComposeSegment"},"propertyName":"type"}},"title":"Segments","maxItems":50,"minItems":1,"description":"Speech and pause segments in output order. Provide 1–50 segments with at least one `tts` segment."}},"description":"A sequence of speech and pause segments returned as one audio file."},"example":{"segments":[{"text":"Welcome to today's update.","type":"tts","model":"ssfm-v30","output":{"audio_format":"wav"},"language":"eng","voice_id":"tc_672c5f5ce59fac2a48faeaee"},{"type":"pause","duration_seconds":1.5},{"text":"Here is the first story.","type":"tts","model":"ssfm-v30","output":{"audio_format":"wav"},"language":"eng","voice_id":"tc_66aca22c7d31e45ff05ff418"}]}}},"required":true,"description":""},"x-codeSamples":[{"lang":"cURL","label":"cURL (save to file)","source":"curl --request POST \\\n  --url https://api.typecast.ai/v1/text-to-speech/compose \\\n  --header 'Content-Type: application/json' \\\n  --header 'X-API-KEY: <api-key>' \\\n  --output output.wav \\\n  --data @- <<EOF\n{\n  \"segments\": [\n    {\n      \"type\": \"tts\",\n      \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n      \"text\": \"Welcome to today's update.\",\n      \"model\": \"ssfm-v30\",\n      \"language\": \"eng\",\n      \"output\": { \"audio_format\": \"wav\" }\n    },\n    { \"type\": \"pause\", \"duration_seconds\": 1.5 },\n    {\n      \"type\": \"tts\",\n      \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n      \"text\": \"Here is the first story.\",\n      \"model\": \"ssfm-v30\",\n      \"language\": \"eng\",\n      \"output\": { \"audio_format\": \"wav\" }\n    }\n  ]\n}\nEOF\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nresponse = requests.post(\n    \"https://api.typecast.ai/v1/text-to-speech/compose\",\n    headers={\"X-API-KEY\": \"<api-key>\"},\n    json={\n        \"segments\": [\n            {\n                \"type\": \"tts\",\n                \"voice_id\": \"tc_672c5f5ce59fac2a48faeaee\",\n                \"text\": \"Welcome to today's update.\",\n                \"model\": \"ssfm-v30\",\n                \"language\": \"eng\",\n                \"output\": {\"audio_format\": \"wav\"}\n            },\n            {\"type\": \"pause\", \"duration_seconds\": 1.5},\n            {\n                \"type\": \"tts\",\n                \"voice_id\": \"tc_66aca22c7d31e45ff05ff418\",\n                \"text\": \"Here is the first story.\",\n                \"model\": \"ssfm-v30\",\n                \"language\": \"eng\",\n                \"output\": {\"audio_format\": \"wav\"}\n            }\n        ]\n    },\n    timeout=120,\n)\nresponse.raise_for_status()\nwith open(\"output.wav\", \"wb\") as audio_file:\n    audio_file.write(response.content)\n"},{"lang":"cURL","label":"Silence removal","source":"curl --request POST 'https://api.typecast.ai/v1/text-to-speech/compose' \\\n  --header 'X-API-KEY: <api-key>' \\\n  --header 'Content-Type: application/json' \\\n  --output review.wav \\\n  --data-binary @- <<'JSON'\n{\n  \"segments\": [\n    {\n      \"type\": \"tts\",\n      \"voice_id\": \"<voice-id>\",\n      \"text\": \"Hello. Thank you for listening.\",\n      \"model\": \"ssfm-v30\",\n      \"output\": {\n        \"audio_format\": \"wav\",\n        \"remove_silence_ms\": 300\n      }\n    },\n    {\n      \"type\": \"pause\",\n      \"duration_seconds\": 1.5\n    },\n    {\n      \"type\": \"tts\",\n      \"voice_id\": \"<voice-id>\",\n      \"text\": \"Hello. Thank you for listening.\",\n      \"model\": \"ssfm-v30\",\n      \"output\": {\n        \"audio_format\": \"wav\",\n        \"remove_silence_ms\": 300\n      }\n    }\n  ]\n}\nJSON\n"}]}},"/v1/voices/recommendations":{"get":{"tags":["Voices"],"x-mint":{"href":"/api-reference/voices/recommend-voices"},"summary":"Recommend Voices","responses":{"200":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RecommendedVoice"},"title":"Response Recommend Voices V1 Voices Recommendations Get","maxItems":10},"example":[{"score":0.92,"voice_id":"tc_60e5426de8b95f1d3000d7b5","voice_name":"Olivia"},{"score":0.87,"voice_id":"tc_62a8975e695ad26f7fb514d1","voice_name":"Emma"}]}},"description":"Success - Returns recommended voices sorted by score"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Invalid or missing API key"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"},"example":{"detail":[{"loc":["query","query"],"msg":"String should have at most 500 characters","type":"string_too_long"}]}}},"description":"Validation Error - Invalid request parameters"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"An unexpected error occurred"}}},"description":"Internal Server Error - Voice recommendation failed"}},"parameters":[{"in":"query","name":"query","schema":{"type":"string","title":"Query","maxLength":500,"minLength":1,"description":"Text description. Describe the desired style, mood, language, use case, or content context with keywords or sentences."},"example":"warm female voice for product tutorial","required":true,"description":"Text description. Describe the desired style, mood, language, use case, or content context with keywords or sentences."},{"in":"query","name":"count","schema":{"type":"integer","title":"Count","default":5,"maximum":10,"minimum":1,"description":"Maximum number of recommended voices to return after filtering. Must be between 1 and 10. Fewer than `count` voices may be returned when there are not enough matching candidates."},"example":5,"required":false,"description":"Maximum number of recommended voices to return after filtering. Must be between 1 and 10. Fewer than `count` voices may be returned when there are not enough matching candidates."}],"description":"This API recommends the best Typecast voices based on text descriptions.\n\nInstead of manually searching for a specific `voice_id`, you can find the perfect voice by simply inputting keywords or sentences describing the desired style, mood, language, or use case. The response is sorted by recommendation score, so you can pass the top candidate directly to text-to-speech endpoints such as `POST /v1/text-to-speech`.\n\nThe response includes only `voice_id`, `voice_name`, and `score`. Use `GET /v3/voices` or `GET /v3/voices/{voice_id}` when you need detailed metadata such as supported models, emotions, gender, age, or use cases for the recommended voices.","operationId":"recommend_voices_v1_voices_recommendations_get","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request GET \\\n  --url 'https://api.typecast.ai/v1/voices/recommendations?query=warm%20female%20voice%20for%20product%20tutorial&count=5' \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nresponse = requests.get(\n    \"https://api.typecast.ai/v1/voices/recommendations\",\n    headers={\"X-API-KEY\": \"<api-key>\"},\n    params={\n        \"query\": \"warm female voice for product tutorial\",\n        \"count\": 5\n    },\n    timeout=30,\n)\nresponse.raise_for_status()\n\nrecommendations = response.json()\nif recommendations:\n    print(recommendations[0][\"voice_id\"])\n"}]}},"/v1/custom-voices/{voice_id}":{"get":{"tags":["Custom Voices"],"x-mint":{"href":"/api-reference/custom-voices/get-custom-voice"},"summary":"Get Custom Voice","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomVoiceItem"},"example":{"name":"Brand Voice","error":null,"model":"ssfm-v30","source":"professional","status":"training","voice_id":"uc_6700000000000000000000bb","created_at":"2026-08-26T04:20:00Z"}}},"description":"Custom voice retrieved successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Invalid voice ID","error_code":"INVALID_VOICE_ID"}}},"description":"The custom voice ID format is invalid"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Custom voice not found","error_code":"CUSTOM_VOICE_NOT_FOUND"}}},"description":"The custom voice does not exist, was deleted, or belongs to another account"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid voice ID"}},"parameters":[{"in":"path","name":"voice_id","schema":{"type":"string","title":"Voice Id"},"required":true,"description":"Unique custom voice identifier."}],"description":"Returns one non-deleted custom voice owned by the authenticated account. Poll this endpoint after starting professional cloning and stop when `status` becomes `completed` or `failed`.","operationId":"get_custom_voice_v1_custom_voices__voice_id__get","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request GET \\\n  --url https://api.typecast.ai/v1/custom-voices/uc_6700000000000000000000bb \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nresponse = requests.get(\n    \"https://api.typecast.ai/v1/custom-voices/uc_6700000000000000000000bb\",\n    headers={\"X-API-KEY\": \"<api-key>\"},\n    timeout=30,\n)\nresponse.raise_for_status()\nprint(response.json())\n"}]},"delete":{"tags":["Custom Voices"],"x-mint":{"href":"/api-reference/custom-voices/delete-custom-voice"},"summary":"Delete Custom Voice","responses":{"204":{"description":"Custom voice deleted successfully"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Invalid voice ID","error_code":"INVALID_VOICE_ID"}}},"description":"The custom voice ID format is invalid"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Custom voice not found","error_code":"CUSTOM_VOICE_NOT_FOUND"}}},"description":"The custom voice does not exist, was deleted, or belongs to another account"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid request format"}}},"description":"Validation Error - Invalid voice ID"}},"parameters":[{"in":"path","name":"voice_id","schema":{"type":"string","title":"Voice Id"},"required":true,"description":"Unique custom voice identifier."}],"description":"Soft-deletes one custom voice owned by the authenticated account, freeing its slot. If a professional clone is still training, the training run is canceled after the voice is deleted.","operationId":"delete_custom_voice_v1_custom_voices__voice_id__delete","x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request DELETE \\\n  --url https://api.typecast.ai/v1/custom-voices/uc_6700000000000000000000bb \\\n  --header 'X-API-KEY: <api-key>'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nresponse = requests.delete(\n    \"https://api.typecast.ai/v1/custom-voices/uc_6700000000000000000000bb\",\n    headers={\"X-API-KEY\": \"<api-key>\"},\n    timeout=30,\n)\nresponse.raise_for_status()\n"}]}},"/v1/custom-voices/instant-clone":{"post":{"tags":["Custom Voices"],"x-mint":{"href":"/api-reference/custom-voices/create-instant-clone"},"summary":"Create Instant Clone","responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomVoiceCreateResponse"},"example":{"name":"Product Narrator","model":"ssfm-v30","status":"completed","voice_id":"uc_6700000000000000000000aa"}}},"description":"Instant clone created successfully"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Custom voice slot limit exceeded","error_code":"CUSTOM_VOICE_SLOT_EXCEEDED"}}},"description":"Custom voice creation is unavailable or no custom voice slot remains"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"File size exceeds maximum limit","error_code":"AUDIO_FILE_TOO_LARGE"}}},"description":"The uploaded audio exceeds the configured size limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Requested model is not supported for this voice","error_code":"VOICE_MODEL_NOT_SUPPORTED"}}},"description":"The form, audio format, or selected model is not supported"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Server is temporarily busy. Please retry shortly.","error_code":"SERVER_BUSY"}}},"description":"The cloning service is temporarily at capacity"}},"description":"Creates a synthesis-ready custom voice from one WAV or MP3 recording. Send the audio, a display name, and a supported TTS model as `multipart/form-data`.\n\n**Audio requirements**\n- One WAV or MP3 file\n- File size: 25 MiB or less\n- Duration: 5 to 150 seconds\n\nThe request uses one custom voice slot. A successful response returns the completed voice immediately. Supported models may vary by account and release availability.","operationId":"create_instant_clone_v1_custom_voices_instant_clone_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_instant_clone_v1_custom_voices_instant_clone_post"}}},"required":true,"description":"Multipart form containing the source recording and voice settings."},"x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request POST \\\n  --url https://api.typecast.ai/v1/custom-voices/instant-clone \\\n  --header 'X-API-KEY: <api-key>' \\\n  --form 'file=@voice-sample.wav' \\\n  --form 'name=Product Narrator' \\\n  --form 'model=ssfm-v30'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nwith open(\"voice-sample.wav\", \"rb\") as audio:\n    response = requests.post(\n        \"https://api.typecast.ai/v1/custom-voices/instant-clone\",\n        headers={\"X-API-KEY\": \"<api-key>\"},\n        files={\"file\": audio},\n        data={\"name\": \"Product Narrator\", \"model\": \"ssfm-v30\"},\n        timeout=120,\n    )\nresponse.raise_for_status()\nprint(response.json())\n"}]}},"/v1/text-to-speech/with-timestamps":{"post":{"tags":["Text-to-Speech"],"x-mint":{"href":"/api-reference/text-to-speech/text-to-speech-with-timestamps"},"summary":"Text To Speech with Timestamps","security":[{"ApiKeyAuth":[]}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TTSWithTimestampsResponse"},"example":{"audio":"UklGRs...(base64-encoded audio omitted)","words":[{"end":0.38,"text":"Try","start":0.08},{"end":0.52,"text":"a","start":0.42},{"end":1.26,"text":"5-minute","start":0.56},{"end":1.88,"text":"stretch","start":1.3},{"end":2.18,"text":"when","start":1.92},{"end":2.42,"text":"you","start":2.22},{"end":2.78,"text":"lose","start":2.46},{"end":3.38,"text":"focus.","start":2.82}],"characters":[{"end":0.18,"text":"T","start":0.08},{"end":0.27,"text":"r","start":0.18},{"end":0.38,"text":"y","start":0.27},{"end":0.42,"text":" ","start":0.38},{"end":0.52,"text":"a","start":0.42},{"end":0.56,"text":" ","start":0.52},{"end":0.7,"text":"5","start":0.56},{"end":0.76,"text":"-","start":0.7},{"end":0.86,"text":"m","start":0.76},{"end":0.94,"text":"i","start":0.86},{"end":1.04,"text":"n","start":0.94},{"end":1.12,"text":"u","start":1.04},{"end":1.2,"text":"t","start":1.12},{"end":1.26,"text":"e","start":1.2},{"end":1.3,"text":" ","start":1.26},{"end":1.4,"text":"s","start":1.3},{"end":1.47,"text":"t","start":1.4},{"end":1.56,"text":"r","start":1.47},{"end":1.64,"text":"e","start":1.56},{"end":1.72,"text":"t","start":1.64},{"end":1.8,"text":"c","start":1.72},{"end":1.88,"text":"h","start":1.8},{"end":1.92,"text":" ","start":1.88},{"end":2.02,"text":"w","start":1.92},{"end":2.08,"text":"h","start":2.02},{"end":2.14,"text":"e","start":2.08},{"end":2.18,"text":"n","start":2.14},{"end":2.22,"text":" ","start":2.18},{"end":2.3,"text":"y","start":2.22},{"end":2.38,"text":"o","start":2.3},{"end":2.42,"text":"u","start":2.38},{"end":2.46,"text":" ","start":2.42},{"end":2.56,"text":"l","start":2.46},{"end":2.64,"text":"o","start":2.56},{"end":2.72,"text":"s","start":2.64},{"end":2.78,"text":"e","start":2.72},{"end":2.82,"text":" ","start":2.78},{"end":2.92,"text":"f","start":2.82},{"end":3.02,"text":"o","start":2.92},{"end":3.12,"text":"c","start":3.02},{"end":3.22,"text":"u","start":3.12},{"end":3.32,"text":"s","start":3.22},{"end":3.38,"text":".","start":3.32}],"audio_format":"wav","audio_duration":3.38}}},"description":"Success - Returns base64 audio and timestamps"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid voice_id"}}},"description":"Bad Request - Invalid parameters"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Unauthorized - Authentication failed"},"402":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Insufficient credit"}}},"description":"Payment Required - Insufficient credits"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Voice not found"}}},"description":"Not Found - Voice model not available"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text.","error_code":"TEXT_NOT_SYNTHESIZABLE"}}},"description":"Validation Error - The request is invalid or the input text cannot be synthesized"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Too many requests"}}},"description":"Too Many Requests - Rate limit exceeded"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"An unexpected error occurred"}}},"description":"Internal Server Error - TTS generation or timestamp alignment failed"}},"deprecated":false,"parameters":[{"in":"query","name":"granularity","schema":{"enum":["word","char"],"type":"string"},"required":false,"description":"Filter for which timestamp arrays to return.\r\n\r\n* Omitted: returns both `words` and `characters`.\r\n* `word`: returns `words` only (`characters` is null).\r\n* `char`: returns `characters` only (`words` is null).\r\n\r\n**Languages without whitespace (e.g., `jpn`, `zho`):** `word` alignment yields a single segment covering the whole sentence, so use `char` to obtain meaningful timestamps."}],"description":"Generate speech from text **and** return word/character-level timestamps aligned with the audio. Useful for subtitle sync, per-character highlight animation, and speech-region visualization.\r\n\r\nThe request body matches the standard `/v1/text-to-speech` endpoint (voice_id, text, model, language, prompt, output). Instead of raw audio bytes, this endpoint returns a JSON object containing base64-encoded audio plus `words` and `characters` arrays.\r\n\r\nUse the optional `granularity` query parameter to return only word-level or only character-level timestamps and reduce payload size.\r\n\r\n> **Language note.** For languages that do not use whitespace between words — such as Japanese (`jpn`) and Chinese (`zho`) — word-level alignment collapses the entire sentence into a single \"word\". For those languages, always request `granularity=char` to receive usable per-character timestamps.\r\n\r\nSee [Listing all voices](/docs/api-reference/voices/list-voices) for available voices.","operationId":"text_to_speech_with_timestamps_v1_text_to_speech_with_timestamps_post","requestBody":{"content":{"application/json":{"schema":{"type":"object","title":"TTSRequestWith-timestampsWith-timestamps","required":["text","model","voice_id"],"properties":{"text":{"type":"string","title":"Text","example":"Everything is so incredibly perfect that I feel like I'm dreaming.","maxLength":2000,"minLength":1,"description":"Text to convert to speech. Minimum 1 character, maximum 2000 characters. Credits consumed based on text length. Supports multiple languages including English, Korean, Japanese, and Chinese. Special characters and punctuation are handled automatically."},"model":{"$ref":"#/components/schemas/TTSModel","example":"ssfm-v30","description":"Voice model to use for speech synthesis.\r\n\r\n* **ssfm-v30**: Latest model with improved prosody and additional emotion presets (recommended)\r\n* **ssfm-v21**: Stable production model with reliable quality"},"output":{"type":"object","title":"","properties":{"volume":{"anyOf":[{"type":"integer","maximum":200,"minimum":0},{"type":"null"}],"title":"Volume","example":100,"description":"Adjusts the relative volume of the output audio: 0 (completely silent), 50 (half volume), 100 (standard volume, default), 150 (50% louder than standard), 200 (maximum volume, twice as loud as standard).\r\n\r\nSince this only scales the existing volume, using `volume` can amplify the loudness differences between voices if they have different baseline levels. For consistent output across all clips, use `target_lufs` instead.\r\n\r\n- **Note:** This parameter cannot be used simultaneously with the `target_lufs` parameter.\r\n\r\nRequired range: 0 <= x <= 200\r\n"},"audio_pitch":{"type":"integer","title":"Audio Pitch","default":0,"example":0,"maximum":12,"minimum":-12,"description":"Adjusts the pitch in semitones to affect perceived gender and age: -12 (one octave lower, deeper voice), -6 (half octave lower), 0 (original pitch, default), +6 (half octave higher), +12 (one octave higher, higher voice)"},"audio_tempo":{"type":"number","title":"Audio Tempo","default":1,"example":1,"maximum":2,"minimum":0.5,"description":"Controls speech speed: 0.5 (half speed, very slow and clear), 0.75 (slightly slower than normal), 1.0 (normal speaking speed, default), 1.5 (50% faster than normal), 2.0 (double speed, very fast speech)"},"target_lufs":{"anyOf":[{"type":"number","maximum":0,"minimum":-70},{"type":"null"}],"title":"Target Lufs","example":-14,"description":"Sets the target absolute loudness (LUFS) for the output audio. This normalizes all generated voices to a consistent volume level, regardless of the original source's loudness. Values closer to 0 are louder, while values closer to -70 are quieter.\r\n\r\n- Required range: -70 <= x <= 0\r\n- Recommended values: -14 (common streaming standard), -23 (broadcast standard)\r\n- **Note:** This parameter cannot be used simultaneously with the `volume` parameter. Use `target_lufs` for consistent absolute loudness across different clips, or use `volume` for traditional relative scaling.\r\n"},"audio_format":{"enum":["wav","mp3"],"type":"string","title":"Audio Format","default":"wav","example":"wav","description":"Output audio format.\r\n\r\n**WAV format:**\r\n- Uncompressed PCM audio\r\n- 16-bit depth, mono channel, 44100 Hz sample rate\r\n- Higher quality, larger file size\r\n- Recommended for professional audio production\r\n\r\n**MP3 format:**\r\n- Compressed MPEG Layer III audio\r\n- 320 kbps bitrate, 44100 Hz sample rate\r\n- Smaller file size\r\n- Recommended for web streaming and distribution\r\n"},"remove_silence_ms":{"anyOf":[{"type":"integer","maximum":1000,"minimum":0},{"type":"null"}],"title":"Remove Silence Ms","default":null,"example":100,"description":"When enabled, shortens detected silences longer than the specified duration to that duration. The value is in milliseconds (ms). The value is the duration of silence to retain, not the amount to remove.\r\n\r\n**Accepted values:**\r\n\r\n- An integer from **0 to 1000**, with a recommended range of 0 to 200.\r\n- Omitted or `null`: silence removal is disabled.\r\n- `0`: removes detected silence longer than 0 ms. **This does not disable the feature.**\r\n- Booleans, strings, fractional values, and out-of-range values are invalid.\r\n\r\n**Example:** `100` shortens detected silences longer than 100 ms to 100 ms. Lower values include shorter silence segments for removal and leave less silence in each affected segment."}},"description":"Audio output settings including volume (0-200), pitch (-12 to +12 semitones), tempo (0.5x to 2.0x), and format (wav/mp3) for controlling the final audio characteristics\r\n\r\nUse `remove_silence_ms` (integer, 0–1000 ms) to shorten detected silence."},"prompt":{"oneOf":[{"$ref":"#/components/schemas/SmartPrompt"},{"$ref":"#/components/schemas/PresetPrompt"},{"$ref":"#/components/schemas/Prompt"}],"title":"Prompt","description":"Emotion and style settings for the generated speech, including emotion type (happy/sad/angry/normal) and intensity (0.0 to 2.0) to control the emotional expression"},"language":{"type":"string","title":"Language","example":"eng","description":"Language code following ISO 639-3 standard. Case-insensitive (both \"ENG\" and \"eng\" are accepted). If not provided, will be auto-detected based on text content.\r\n\r\n<details>\r\n  <summary><strong>ssfm-v30 Supported Languages (37)</strong></summary>\r\n\r\n  | Code | Language  | Code | Language   | Code | Language   |\r\n  | ---- | --------- | ---- | ---------- | ---- | ---------- |\r\n  | ARA  | Arabic    | IND  | Indonesian | POR  | Portuguese |\r\n  | BEN  | Bengali   | ITA  | Italian    | RON  | Romanian   |\r\n  | BUL  | Bulgarian | JPN  | Japanese   | RUS  | Russian    |\r\n  | CES  | Czech     | KOR  | Korean     | SLK  | Slovak     |\r\n  | DAN  | Danish    | MSA  | Malay      | SPA  | Spanish    |\r\n  | DEU  | German    | NAN  | Min Nan    | SWE  | Swedish    |\r\n  | ELL  | Greek     | NLD  | Dutch      | TAM  | Tamil      |\r\n  | ENG  | English   | NOR  | Norwegian  | TGL  | Tagalog    |\r\n  | FIN  | Finnish   | PAN  | Punjabi    | THA  | Thai       |\r\n  | FRA  | French    | POL  | Polish     | TUR  | Turkish    |\r\n  | HIN  | Hindi     | UKR  | Ukrainian  | VIE  | Vietnamese |\r\n  | HRV  | Croatian  | YUE  | Cantonese  | ZHO  | Chinese    |\r\n  | HUN  | Hungarian |      |            |      |            |\r\n</details>\r\n\r\n<details>\r\n  <summary><strong>ssfm-v21 Supported Languages (27)</strong></summary>\r\n\r\n  | Code | Language  | Code | Language   | Code | Language  |\r\n  | ---- | --------- | ---- | ---------- | ---- | --------- |\r\n  | ARA  | Arabic    | IND  | Indonesian | RON  | Romanian  |\r\n  | BUL  | Bulgarian | ITA  | Italian    | RUS  | Russian   |\r\n  | CES  | Czech     | JPN  | Japanese   | SLK  | Slovak    |\r\n  | DAN  | Danish    | KOR  | Korean     | SPA  | Spanish   |\r\n  | DEU  | German    | MSA  | Malay      | SWE  | Swedish   |\r\n  | ELL  | Greek     | NLD  | Dutch      | TAM  | Tamil     |\r\n  | ENG  | English   | POL  | Polish     | TGL  | Tagalog   |\r\n  | FIN  | Finnish   | POR  | Portuguese | UKR  | Ukrainian |\r\n  | FRA  | French    | HRV  | Croatian   | ZHO  | Chinese   |\r\n</details>\r\n\r\n> **Timestamp endpoint note.** For languages without inter-word whitespace — Japanese (`jpn`) and Chinese (`zho`) — word-level alignment collapses the whole sentence into a single segment. Always pair these languages with `granularity=char` to receive usable per-character timestamps."},"voice_id":{"type":"string","title":"Voice Id","example":"tc_60e5426de8b95f1d3000d7b5","description":"Voice identifier. Two prefixes are supported:\r\n\r\n* `tc_` — Built-in Typecast voices (e.g., `tc_60e5426de8b95f1d3000d7b5`). See [Listing all voices](/docs/api-reference/voices/list-voices) for available IDs.\r\n* `uc_` — Custom voices created via [Instant cloning](/docs/api-reference/voices/instant-cloning) (e.g., `uc_64a1b2c3d4e5f6a7b8c9d0e1`). Only the owner of a cloned voice can use it.\r\n\r\nCase-sensitive: must use lowercase prefix."}},"description":"Text-to-speech request parameters"}}},"required":true,"description":""},"x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request POST \\\r\n  --url https://api.typecast.ai/v1/text-to-speech/with-timestamps \\\r\n  --header 'Content-Type: application/json' \\\r\n  --header 'X-API-KEY: <api-key>' \\\r\n  --data @- <<EOF\r\n{\r\n  \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n  \"text\": \"Try a 5-minute stretch when you lose focus.\",\r\n  \"model\": \"ssfm-v30\",\r\n  \"language\": \"eng\",\r\n  \"prompt\": {\r\n    \"emotion_type\": \"preset\",\r\n    \"emotion_preset\": \"normal\",\r\n    \"emotion_intensity\": 1.0\r\n  }\r\n}\r\nEOF\r\n"},{"lang":"Python","label":"Python (requests)","source":"import base64\r\nimport requests\r\n\r\nAPI_HOST = \"https://api.typecast.ai\"\r\nheaders = {\r\n    \"X-API-KEY\": \"<api-key>\",\r\n    \"Content-Type\": \"application/json\"\r\n}\r\npayload = {\r\n    \"voice_id\": \"tc_60e5426de8b95f1d3000d7b5\",\r\n    \"text\": \"Try a 5-minute stretch when you lose focus.\",\r\n    \"model\": \"ssfm-v30\",\r\n    \"language\": \"eng\",\r\n    \"prompt\": {\r\n        \"emotion_type\": \"preset\",\r\n        \"emotion_preset\": \"normal\",\r\n        \"emotion_intensity\": 1.0\r\n    }\r\n}\r\n\r\nresponse = requests.post(\r\n    f\"{API_HOST}/v1/text-to-speech/with-timestamps\",\r\n    headers=headers,\r\n    json=payload,\r\n    timeout=60,\r\n)\r\nresponse.raise_for_status()\r\ndata = response.json()\r\n\r\nwith open(\"output.wav\", \"wb\") as f:\r\n    f.write(base64.b64decode(data[\"audio\"]))\r\nprint(f\"Saved {len(data['audio'])} base64 chars; duration={data['audio_duration']}s\")\r\nfor w in (data.get(\"words\") or [])[:3]:\r\n    print(f\"  word: {w['text']!r} {w['start']:.3f}s - {w['end']:.3f}s\")\r\n"},{"lang":"cURL","label":"Silence removal","source":"curl --request POST 'https://api.typecast.ai/v1/text-to-speech/with-timestamps' \\\r\n  --header 'X-API-KEY: <api-key>' \\\r\n  --header 'Content-Type: application/json' \\\r\n  --output review.json \\\r\n  --data-binary @- <<'JSON'\r\n{\r\n  \"voice_id\": \"<voice-id>\",\r\n  \"text\": \"Hello. Thank you for listening.\",\r\n  \"model\": \"ssfm-v30\",\r\n  \"output\": {\r\n    \"audio_format\": \"wav\",\r\n    \"remove_silence_ms\": 300\r\n  }\r\n}\r\nJSON\r\n"}]}},"/v1/custom-voices/professional-clone":{"post":{"tags":["Custom Voices"],"x-mint":{"href":"/api-reference/custom-voices/create-professional-clone"},"summary":"Create Professional Clone","security":[{"ApiKeyAuth":[]}],"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomVoiceCreateResponse"},"example":{"name":"Custom Voice Name","model":"ssfm-v30","status":"training","voice_id":"uc_6700000000000000000000bb"}}},"description":"Professional clone training started successfully"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"detail":"Invalid API key"}}},"description":"Authentication failed"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Professional voice slot limit exceeded","error_code":"PROFESSIONAL_VOICE_SLOT_EXCEEDED"}}},"description":"Professional cloning is unavailable or no professional voice slot remains"},"413":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"File size exceeds maximum limit","error_code":"AUDIO_FILE_TOO_LARGE"}}},"description":"The combined upload exceeds the configured size limit"},"422":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Requested language is not supported for the selected model","error_code":"LANGUAGE_NOT_SUPPORTED"}}},"description":"The language, form, audio format, or selected model is not supported"},"503":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"message":"Server is temporarily busy. Please retry shortly.","error_code":"SERVER_BUSY"}}},"description":"The professional cloning service is temporarily at capacity"}},"deprecated":false,"description":"Starts asynchronous professional voice training from WAV or MP3 recordings. Send the recordings, display name, supported TTS model, and an ISO 639-3 language code as `multipart/form-data`.\r\n\r\n**Audio requirements**\r\n\r\n* One WAV or MP3 file\r\n* File size: 1 GiB or less\r\n* Duration: 5 minutes to 3 hours\r\n* Sample rate: 16 kHz or higher\r\n\r\nA successful request returns `202 Accepted` with `status: training`. Poll `GET /v1/custom-voices/{voice_id}` until the status becomes `completed` or `failed`.&#x20;\r\n\r\nTraining may take up to two hours. You’ll receive an email when custom voice training is complete or if it fails.","operationId":"create_professional_clone_v1_custom_voices_professional_clone_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_professional_clone_v1_custom_voices_professional_clone_post"}}},"required":true,"description":"Multipart form containing training audio and voice settings."},"x-codeSamples":[{"lang":"cURL","label":"cURL","source":"curl --request POST \\\n  --url https://api.typecast.ai/v1/custom-voices/professional-clone \\\n  --header 'X-API-KEY: <api-key>' \\\n  --form 'files=@training-audio.wav' \\\n  --form 'name=Custom Voice Name' \\\n  --form 'model=ssfm-v30' \\\n  --form 'language=eng'\n"},{"lang":"Python","label":"Python (requests)","source":"import requests\n\nwith open(\"training-audio.wav\", \"rb\") as audio:\n    response = requests.post(\n        \"https://api.typecast.ai/v1/custom-voices/professional-clone\",\n        headers={\"X-API-KEY\": \"<api-key>\"},\n        files=[(\"files\", audio)],\n        data={\"name\": \"Brand Voice\", \"model\": \"ssfm-v30\", \"language\": \"eng\"},\n        timeout=120,\n    )\nresponse.raise_for_status()\nprint(response.json())\n"}]}}},"openapi":"3.1.0","servers":[{"url":"https://api.typecast.ai","description":"Production server"}],"security":[{"ApiKeyAuth":[]}],"components":{"schemas":{"Limits":{"type":"object","title":"Limits","required":["concurrency_limit"],"properties":{"concurrency_limit":{"type":"integer","title":"Concurrency Limit","description":"Maximum number of concurrent requests allowed"},"custom_voice_slot":{"type":"integer","title":"Custom Voice Slot","default":0,"minimum":0,"description":"Maximum number of custom voices (created via instant cloning) allowed on the current plan."},"professional_voice_slot":{"type":"integer","title":"Professional Voice Slot","default":0,"minimum":0,"description":"프리미엄 클로닝 보이스 슬롯 한도"}},"description":"Usage limit information"},"Prompt":{"title":"Prompt (ssfm-v21)","properties":{"emotion_preset":{"example":"normal","description":"Emotion preset to apply.\r\n\r\nSupported emotions for ssfm-v21: normal, happy, sad, angry\r\n\r\nCheck available emotions for each voice in the `models` field of the `GET /v3/voices` API response.\r\n"},"emotion_intensity":{"example":1,"description":"Controls the strength of emotional expression (0.0 to 2.0).\r\n\r\n- 0.0: Completely neutral\r\n- 1.0: Standard expression (default)\r\n- 2.0: Maximum intensity\r\n"}},"description":"Emotion and style settings for the generated speech."},"AgeEnum":{"enum":["child","teenager","young_adult","middle_age","elder"],"type":"string","title":"AgeEnum","description":"Age group classification enum - Converts database values (Korean) to API values (English).\n\nAvailable values:\n- **child**: Child voice (under 12 years old)\n- **teenager**: Teenage voice (13-19 years old)\n- **young_adult**: Young adult voice (20-35 years old)\n- **middle_age**: Middle-aged voice (36-60 years old)\n- **elder**: Elder voice (over 60 years old)\n"},"Credits":{"type":"object","title":"Credits","required":["plan_credits","used_credits"],"properties":{"plan_credits":{"type":"integer","title":"Plan Credits","description":"Total monthly credits provided by the plan"},"used_credits":{"type":"integer","title":"Used Credits","description":"Number of credits used"}},"description":"Credit usage information"},"VoiceV2":{"type":"object","title":"VoiceV2","required":["voice_id","voice_name","models","voice_type"],"properties":{"age":{"anyOf":[{"$ref":"#/components/schemas/AgeEnum"},{"type":"null"}],"description":"Voice age group classification (child/teenager/young_adult/middle_age/elder)"},"gender":{"anyOf":[{"$ref":"#/components/schemas/GenderEnum"},{"type":"null"}],"description":"Voice gender classification (male/female)"},"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"},"title":"Models","description":"List of supported TTS models with their available emotions (e.g., [{'version': 'ssfm-v21', 'emotions': ['happy', 'sad']}])"},"voice_id":{"type":"string","title":"Voice Id","description":"Unique voice identifier. Built-in voices use the `tc_` prefix (e.g., `tc_60e5426de8b95f1d3000d7b5`); cloned custom voices created via `POST /v1/voices/clone` use the `uc_` prefix. Use `/v3/voices` to list the built-in and completed custom voices available to your account."},"use_cases":{"type":"array","items":{"type":"string"},"title":"Use Cases","description":"List of use case categories this voice is suitable for"},"voice_name":{"type":"string","title":"Voice Name","description":"Human-readable name of the voice"},"voice_type":{"$ref":"#/components/schemas/VoiceType","description":"Voice type — `original` for Typecast-provided stock voices, `custom` for user-cloned voices."}},"description":"V2 Voice response model with model-grouped emotions and enhanced metadata"},"VoiceV3":{"type":"object","title":"VoiceV3","required":["voice_id","voice_name","voice_type","models"],"properties":{"age":{"anyOf":[{"$ref":"#/components/schemas/AgeEnum"},{"type":"null"}],"description":"Voice age group."},"gender":{"anyOf":[{"$ref":"#/components/schemas/GenderEnum"},{"type":"null"}],"description":"Voice gender (`male` or `female`)."},"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelInfo"},"title":"Models","description":"Supported TTS models and their available emotions."},"voice_id":{"type":"string","title":"Voice Id","description":"Unique voice identifier. Built-in voices use the `tc_` prefix and custom voices use the `uc_` prefix."},"use_cases":{"type":"array","items":{"type":"string"},"title":"Use Cases","description":"Recommended use-case categories."},"voice_name":{"$ref":"#/components/schemas/VoiceName","description":"Localized voice names, such as `{\"eng\": \"Daejin\", \"kor\": \"대진\"}`."},"voice_type":{"$ref":"#/components/schemas/VoiceType","description":"Voice type (`original` or `custom`)."},"preview_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview Url","description":"Preview audio URL when available."}},"description":"Voice metadata with localized names and a preview audio URL."},"PlanTier":{"enum":["free","lite","plus","custom"],"type":"string","title":"PlanTier","description":"Subscription plan for the API.\n\nAvailable values:\n- **free**: Free tier with limited credits\n- **lite**: Lite plan with moderate credits\n- **plus**: Plus plan with higher credits\n- **custom**: Custom enterprise plan"},"TTSModel":{"enum":["ssfm-v30","ssfm-v21"],"type":"string","title":"TTSModel","description":"TTS model version to use for speech synthesis. Different models offer varying capabilities and quality levels.\n\nAvailable models:\n- **ssfm-v30**: Latest model with improved prosody and additional emotion presets (recommended)\n- **ssfm-v21**: Stable production model with proven reliability and consistent quality\n"},"ModelInfo":{"type":"object","title":"ModelInfo","required":["version","emotions"],"properties":{"version":{"$ref":"#/components/schemas/TTSModel","description":"TTS model version (e.g., ssfm-v21, ssfm-v30)"},"emotions":{"type":"array","items":{"type":"string"},"title":"Emotions","description":"List of supported emotions for this model"}},"description":"Model information including version and supported emotions"},"VoiceName":{"type":"object","title":"VoiceName","required":["eng","kor"],"properties":{"eng":{"type":"string","title":"Eng","description":"English voice name."},"kor":{"type":"string","title":"Kor","description":"Korean voice name."}},"description":"Localized voice names keyed by ISO 639-3 language code."},"VoiceType":{"enum":["original","custom"],"type":"string","title":"VoiceType","description":"Voice type classification.\n\n- `original` — Typecast-provided stock voices available to every account.\n- `custom` — Voices the user created by uploading or cloning their own sample."},"GenderEnum":{"enum":["male","female"],"type":"string","title":"GenderEnum","description":"Gender classification enum - Converts database values (Korean) to API values (English).\n\nAvailable values:\n- **male**: Male voice\n- **female**: Female voice\n"},"EmotionEnum":{"enum":["normal","sad","happy","angry","whisper","toneup","tonedown"],"type":"string","title":"EmotionEnum","description":"Available emotion presets for speech synthesis. Each emotion affects the tone, pace, and expressiveness of the generated speech.\n\n**ssfm-v21 Supported Emotions (4 types):**\n- normal: Neutral, balanced tone\n- happy: Bright, cheerful expression\n- sad: Melancholic, subdued tone\n- angry: Strong, intense delivery\n\n**ssfm-v30 Supported Emotions (7 types):**\n- normal: Neutral, balanced tone\n- happy: Bright, cheerful expression\n- sad: Melancholic, subdued tone\n- angry: Strong, intense delivery\n- whisper: Soft, quiet speech\n- toneup: Higher tonal emphasis\n- tonedown: Lower tonal emphasis\n\nCheck available emotions for each voice in the `models` field of the `GET /v3/voices` API response.\n"},"SmartPrompt":{"type":"object","title":"SmartPrompt (ssfm-v30)","example":{"next_text":"I am literally bursting with happiness and I never want this feeling to end!","emotion_type":"smart","previous_text":"I feel like I'm walking on air and I just want to scream with joy!"},"properties":{"next_text":{"type":"string","title":"Next Text","default":"","example":"I am literally bursting with happiness and I never want this feeling to end!","description":"Text that comes AFTER the `text` field in TTSRequest. Provides forward context for emotion inference.\r\n\r\nThe model analyzes the flow: `previous_text` → `text` (synthesized) → `next_text`\r\n\r\n- Maximum 2000 characters\r\n- Helps the model anticipate emotional transitions\r\n- Leave empty if no following context is available\r\n"},"emotion_type":{"type":"string","const":"smart","title":"Emotion Type","default":"smart","description":"Discriminator field to identify the prompt type. Must be set to \"smart\" for context-aware emotion inference.\r\n"},"previous_text":{"type":"string","title":"Previous Text","default":"","example":"I feel like I'm walking on air and I just want to scream with joy!","description":"Text that comes BEFORE the `text` field in TTSRequest. Provides backward context for emotion inference.\r\n\r\nThe model analyzes the flow: `previous_text` → `text` (synthesized) → `next_text`\r\n\r\n- Maximum 2000 characters\r\n- Helps the model understand emotional build-up and context\r\n- Leave empty if no preceding context is available\r\n"}},"description":"Emotion and style settings for the generated speech.","additionalProperties":false},"PresetPrompt":{"type":"object","title":"PresetPrompt (ssfm-v30)","properties":{"emotion_type":{"type":"string","const":"preset","title":"Emotion Type","default":"preset","description":"Discriminator field to identify the prompt type. Must be set to \"preset\" for preset-based emotion control.\r\n"},"emotion_preset":{"$ref":"#/components/schemas/EmotionEnum","default":"normal","example":"normal","description":"Emotion preset to apply to the generated speech.\r\n\r\nSupported emotions: normal, happy, sad, angry, whisper, toneup, tonedown\r\n\r\nCheck available emotions for each voice in the `models` field of the `GET /v3/voices` API response.\r\n"},"emotion_intensity":{"type":"number","title":"Emotion Intensity","default":1,"example":1,"maximum":2,"minimum":0,"description":"Controls the strength of emotional expression in the generated speech.\r\n\r\n- 0.0: Completely neutral, no emotional coloring\r\n- 0.5: Subtle emotional hints\r\n- 1.0: Standard emotional expression (default)\r\n- 1.5: Strong emotional emphasis\r\n- 2.0: Maximum intensity, highly expressive\r\n"}},"description":"Emotion and style settings for the generated speech.","additionalProperties":false},"UseCasesEnum":{"enum":["Announcer","Anime","Audiobook","Conversational","Documentary","E-learning","Rapper","Game","Tiktok/Reels","News","Podcast","Voicemail","Ads"],"type":"string","description":"Voice use case categories for content type filtering. Each voice is tagged with one or more use cases indicating its suitability for specific content types.\n\n**Available Use Cases:**\n- **Announcer**: Public announcements and presentations\n- **Anime**: Animation and character voices\n- **Audiobook**: Long-form narration and storytelling\n- **Conversational**: Chatbots and conversational AI\n- **Documentary**: Documentary narration and commentary\n- **E-learning**: Educational content and tutorials\n- **Rapper**: Rap and music performance\n- **Game**: Video game characters and narration\n- **Tiktok/Reels**: Short-form social media content\n- **News**: News broadcasting\n- **Podcast**: Broadcasting and podcast production\n- **Voicemail**: IVR systems and voice assistants\n- **Ads**: Advertising and promotional content\n"},"ErrorResponse":{"type":"object","example":{"message":"The input text contains characters or symbols that cannot be synthesized into speech. Please check your input text.","error_code":"TEXT_NOT_SYNTHESIZABLE"},"properties":{"detail":{"type":"string","description":"Error message describing the issue"},"message":{"type":"string","description":"Human-readable message for structured errors"},"error_code":{"type":"string","description":"Machine-readable error code for structured errors"}},"description":"API errors use `detail` for legacy and validation errors, or `error_code` and `message` for structured errors."},"CustomVoiceItem":{"type":"object","title":"CustomVoiceItem","required":["voice_id","name","model","source","status","created_at"],"properties":{"name":{"type":"string","title":"Name","description":"Voice name."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Failure reason when `status` is `failed`."},"model":{"type":"string","title":"Model","description":"TTS model version."},"source":{"type":"string","title":"Source","description":"Creation method (`instant` or `professional`)."},"status":{"$ref":"#/components/schemas/CustomVoiceStatus","description":"Current creation or training status."},"voice_id":{"type":"string","title":"Voice Id","description":"Unique custom voice identifier with the `uc_` prefix."},"created_at":{"type":"string","title":"Created At","format":"date-time","description":"Creation time in UTC."}},"description":"A custom voice owned by the authenticated account."},"ValidationError":{"type":"object","title":"ValidationError","required":["loc","msg","type"],"properties":{"ctx":{"type":"object","title":"Context"},"loc":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"}}},"RecommendedVoice":{"type":"object","title":"RecommendedVoice","required":["voice_id","voice_name","score"],"properties":{"score":{"type":"number","title":"Score","example":0.92,"description":"Recommendation relevance score. Higher values indicate a stronger match for the query."},"voice_id":{"type":"string","title":"Voice Id","example":"tc_60e5426de8b95f1d3000d7b5","description":"Typecast voice identifier with the `tc_` prefix. Use this value as `voice_id` in text-to-speech requests."},"voice_name":{"type":"string","title":"Voice Name","example":"Olivia","description":"Human-readable voice name."}},"description":"Recommended voice candidate returned by `GET /v1/voices/recommendations`, sorted by relevance."},"CustomVoiceStatus":{"enum":["pending","training","completed","failed"],"type":"string","title":"CustomVoiceStatus","description":"Current creation or training status of a custom voice."},"CustomVoiceResponse":{"type":"object","title":"CustomVoiceResponse","required":["voice_id","name","model","status"],"properties":{"name":{"type":"string","title":"Name","description":"Human-readable voice name (1-30 characters)."},"model":{"type":"string","allOf":[{"$ref":"#/components/schemas/TTSModel"}],"title":"Model","description":"Engine model the voice was cloned for (`ssfm-v21` or `ssfm-v30`)."},"status":{"$ref":"#/components/schemas/CustomVoiceStatus","description":"생성/학습 상태"},"voice_id":{"type":"string","title":"Voice Id","example":"uc_64a1b2c3d4e5f6a7b8c9d0e1","description":"Custom voice identifier with the `uc_` prefix. Use this value as `voice_id` in `POST /v1/text-to-speech` and other endpoints that accept `voice_id`."}},"description":"Response of `POST /v1/voices/clone` — custom voice metadata returned by instant cloning."},"HTTPValidationError":{"type":"object","title":"HTTPValidationError","properties":{"detail":{"type":"array","items":{"$ref":"#/components/schemas/ValidationError"},"title":"Detail"}}},"PauseComposeSegment":{"type":"object","title":"PauseComposeSegment","examples":[{"type":"pause","duration_seconds":1.5}],"required":["type","duration_seconds"],"properties":{"type":{"type":"string","const":"pause","title":"Type","default":"pause","description":"Segment discriminator. Always `pause`."},"duration_seconds":{"type":"number","title":"Duration Seconds","example":1.5,"maximum":10,"description":"Pause duration in seconds. Each pause may be up to 10 seconds; all pauses combined may be up to 60 seconds.","exclusiveMinimum":0}},"description":"A silent interval inserted without consuming credits.","additionalProperties":false},"AlignmentSegmentWord":{"type":"object","title":"AlignmentSegmentWord","required":["text","start","end"],"properties":{"end":{"type":"number","title":"End","description":"End time of this segment, in seconds from the beginning of the audio."},"text":{"type":"string","title":"Text","description":"The text fragment from the original transcript (includes any attached punctuation)."},"start":{"type":"number","title":"Start","description":"Start time of this segment, in seconds from the beginning of the audio."}},"description":"A single word-level alignment segment between the original transcript and the generated audio."},"SubscriptionResponse":{"type":"object","title":"SubscriptionResponse","required":["plan","credits","limits","professional_clone_generations"],"properties":{"plan":{"$ref":"#/components/schemas/PlanTier","description":"Current subscription plan"},"limits":{"$ref":"#/components/schemas/Limits","description":"Usage limit information"},"credits":{"$ref":"#/components/schemas/Credits","description":"Credit usage information"},"professional_clone_generations":{"$ref":"#/components/schemas/ProfessionalCloneGenerations"}},"description":"Subscription information response model"},"AlignmentSegmentCharacter":{"type":"object","title":"AlignmentSegmentCharacter","required":["text","start","end"],"properties":{"end":{"type":"number","title":"End","description":"End time of this segment, in seconds from the beginning of the audio."},"text":{"type":"string","title":"Text","description":"The text fragment from the original transcript (includes any attached punctuation and whitespace)."},"start":{"type":"number","title":"Start","description":"Start time of this segment, in seconds from the beginning of the audio."}},"description":"A single character-level alignment segment between the original transcript and the generated audio."},"CustomVoiceCreateResponse":{"type":"object","title":"CustomVoiceCreateResponse","required":["voice_id","name","model","status"],"properties":{"name":{"type":"string","title":"Name","description":"Voice name."},"model":{"type":"string","title":"Model","description":"TTS model version."},"status":{"$ref":"#/components/schemas/CustomVoiceStatus","description":"Current creation or training status."},"voice_id":{"type":"string","title":"Voice Id","description":"Unique custom voice identifier with the `uc_` prefix."}},"description":"Result returned after creating an instant or professional custom voice."},"TTSWithTimestampsResponse":{"type":"object","title":"TTSWithTimestampsResponse","required":["audio","audio_format","audio_duration","words","characters"],"properties":{"audio":{"type":"string","title":"Audio","description":"Base64-encoded audio bytes. Decode and write to a file using the `audio_format` extension."},"words":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/AlignmentSegmentWord"}},{"type":"null"}],"title":"Words","description":"Word-level timestamps (with attached punctuation). `null` when the request uses `granularity=char`."},"characters":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/AlignmentSegmentCharacter"}},{"type":"null"}],"title":"Characters","description":"Character-level timestamps (including punctuation and whitespace). `null` when the request uses `granularity=word`."},"audio_format":{"enum":["wav","mp3"],"type":"string","title":"Audio Format","description":"Audio encoding format of the bytes in `audio` — either `wav` or `mp3`, mirroring the request's `output.audio_format`."},"audio_duration":{"type":"number","title":"Audio Duration","description":"Length of the generated audio in seconds."}},"description":"Response payload for POST /v1/text-to-speech/with-timestamps — base64-encoded audio plus per-word and per-character timestamps aligned with the generated speech."},"ProfessionalCloneGenerations":{"type":"object","title":"ProfessionalCloneGenerations","properties":{"plan_generations":{"type":"integer","title":"Plan Generations","default":0,"minimum":0,"description":"플랜 제공 학습 횟수"},"used_generations":{"type":"integer","title":"Used Generations","default":0,"minimum":0,"description":"사용된 학습 횟수"}},"description":"프리미엄 클로닝 학습 횟수 정보"},"Body_create_voice_clone_v1_voices_clone_post":{"type":"object","title":"Body_create_voice_clone_v1_voices_clone_post","required":["file","name","model"],"properties":{"file":{"type":"string","title":"File","format":"binary","description":"Audio sample. WAV or MP3, max 25 MB, 5-150 seconds.","contentMediaType":"application/octet-stream"},"name":{"type":"string","title":"Name","maxLength":30,"minLength":1,"description":"Voice name (1-30 characters)."},"model":{"$ref":"#/components/schemas/TTSModel","allOf":[{"$ref":"#/components/schemas/TTSModel"}],"description":"Engine model the voice is cloned for (`ssfm-v21` or `ssfm-v30`)."}},"description":"Multipart request body for instant cloning."},"Body_create_instant_clone_v1_custom_voices_instant_clone_post":{"type":"object","title":"Body_create_instant_clone_v1_custom_voices_instant_clone_post","required":["file","name","model"],"properties":{"file":{"type":"string","title":"File","format":"binary","description":"One WAV or MP3 recording, 25 MiB or less and 5 to 150 seconds long.","contentMediaType":"application/octet-stream"},"name":{"type":"string","title":"Name","example":"Product Narrator","maxLength":30,"minLength":1,"description":"Voice name, up to 30 characters."},"model":{"$ref":"#/components/schemas/TTSModel","example":"ssfm-v30","description":"TTS model version."}},"description":"Multipart request body for instant voice cloning."},"Body_create_professional_clone_v1_custom_voices_professional_clone_post":{"type":"object","title":"Body_create_professional_clone_v1_custom_voices_professional_clone_post","required":["name","files","model","language"],"properties":{"name":{"type":"string","title":"Name","example":"Custom Voice Name","maxLength":30,"minLength":1,"description":"Voice name, up to 30 characters."},"files":{"type":"array","items":{"type":"string","format":"binary","contentMediaType":"application/octet-stream"},"title":"Files","description":"WAV or MP3 recordings used for training. Only one file can be uploaded.\r\n\r\n**Upload limits**\r\n\r\n* One WAV or MP3 file\r\n* File size: 1 GiB or less\r\n* Duration: 5 minutes to 3 hours\r\n* Sample rate: 16 kHz or higher\r\n\r\nFor best results, we recommend audio that meets the following conditions:\r\n\r\n* Record in a speaking style that closely matches how you want the generated voice to sound.\r\n* Record in a quiet environment without background noise.\r\n* Include only one speaker.\r\n* Record in the language specified in the `language` field.\r\n* Longer input audio results in higher-quality generated voices."},"model":{"$ref":"#/components/schemas/TTSModel","example":"ssfm-v30","description":"TTS model version."},"language":{"type":"string","title":"Language","example":"eng","description":"ISO 639-3 language code, such as `kor` or `eng`."}},"description":"Multipart request body for professional voice cloning."}},"securitySchemes":{"ApiKeyAuth":{"in":"header","name":"X-API-KEY","type":"apiKey","description":"API key for authentication. You can obtain an API key from the Typecast API Console."},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}}}}