# API Status and Version Source: https://docs.cartesia.ai/api-reference/api-status/get latest.yml GET / # Realtime Speech-to-Text (Auto) Source: https://docs.cartesia.ai/api-reference/stt/turns/websocket Realtime speech transcription with built-in turn detection This endpoint is English only right now. We expect to add more languages in the coming months. # Text-to-Speech (Bytes) Source: https://docs.cartesia.ai/api-reference/tts/bytes latest.yml POST /tts/bytes Stream audio from a complete transcript # Text-to-Speech (SSE) Source: https://docs.cartesia.ai/api-reference/tts/sse latest.yml POST /tts/sse Stream audio with extra metadata from a complete transcript # Text-to-Speech (WebSocket) Source: https://docs.cartesia.ai/api-reference/tts/websocket Generate audio in realtime with contexts # Advanced capabilities Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/advanced-capabilities Use Hinglish code-switching and text normalizers to control how Sonic speaks specialized content. Sonic handles most transcripts as-is. The capabilities below cover cases where you want finer control over mixed-language speech and how written forms are spoken. ## Hinglish Sonic supports code-switching between Hindi and English (Hinglish) in a single generation. Pass the transcript in conventional written form — Devanagari, Latin script, or a mix — and the model switches languages naturally mid-sentence. ```python theme={null} from cartesia import Cartesia client = Cartesia(api_key="your-api-key") response = client.tts.generate( model_id="sonic-preview", transcript="आपका order confirm हो गया है। Delivery expected by Friday.", voice="a0e99841-438c-4a64-b679-ae501e7d6091", language="hi", ) audio = response.read() ``` ### Romanized Hindi and Indic text Sonic reads Hindi and other Indic languages written in Latin script — Hinglish and other transliterated text — and follows romanized transcripts materially better in Sonic 3.6, available on `sonic-preview` now. Write romanized text the way it's naturally typed, and keep English words in their standard spelling: ```text theme={null} Aapka order confirm ho gaya hai. Delivery kal shaam tak hogi. ``` Set the `language` field to the language of the transcript (`hi` for Hinglish) even when the text is romanized. Quality varies with how scripts are mixed in the transcript: | Script mix | Example | `language` | `normalization` | | ------------------------------ | ---------------------------------- | ------------- | --------------- | | Pure Devanagari | `आपका औडर आ गया है।` | `hi` | `hi-IN` | | Pure English | `Your order has arrived.` | `en` or `hi` | `en-IN` | | Pure romanized Hindi | `Aapka order aa gaya hai.` | `hi` | `en-IN` | | Romanized Hindi + English | `Aapka order confirm ho gaya hai.` | `hi` | `en-IN` | | Devanagari + English loanwords | `आपका order confirm हो गया है।` | `hi` | `hi-IN` | | Devanagari + romanized Hindi | `आपका order aa gaya hai.` | Not supported | — | | All three scripts | `आपका order confirm ho gaya है।` | Not supported | — | For pure English transcripts, either `en` or `hi` works as the language: the more Indian words the sentence carries — names, places, product terms — the more the `hi` setting pronounces them correctly. Experiment with these settings to find what sounds best for your content. Both `language` and `normalization` are set per generation, so you can vary them transcript by transcript rather than picking one combination for your whole integration. ### Worked examples Accent and reading conventions are independent controls: `locale` picks the voice's accent, `normalization` picks how dates, times, and numbers are read. #### Hindi voice, English digit reading An OTP or confirmation code inside a Hindi transcript should read digit-by-digit the English way: `4821` as "four eight two one" rather than as a Hindi number. ```json theme={null} { "model_id": "sonic-preview", "transcript": "आपका OTP 4821 है।", "voice": "a0e99841-438c-4a64-b679-ae501e7d6091", "locale": "hi", "normalization": "en-IN", "output_format": { "container": "mp3", "sample_rate": 44100, "bit_rate": 128000 } } ``` #### Romanized Hindi with English read-outs The highest-traffic combination: a Hinglish transcript spoken with a Hindi-Indian accent while dates, times, and digits follow English-Indian conventions. ```json theme={null} { "model_id": "sonic-preview", "transcript": "Aapka order 14/08/2026 ko deliver hoga, confirmation code 4821 hai.", "voice": "a0e99841-438c-4a64-b679-ae501e7d6091", "locale": "hi-IN", "normalization": "en-IN", "output_format": { "container": "mp3", "sample_rate": 44100, "bit_rate": 128000 } } ``` ## Normalizers Normalizers control how Sonic expands written forms — numbers, currency, dates, phone numbers — into spoken words. By default, Sonic applies locale-aware normalization automatically, so `$19.99` is spoken as "nineteen dollars and ninety-nine cents". ```python theme={null} response = client.tts.generate( model_id="sonic-preview", transcript="Your total is $19.99, due 04/20/2025.", voice="a0e99841-438c-4a64-b679-ae501e7d6091", ) # Spoken: "Your total is nineteen dollars and ninety-nine cents, due April twentieth, twenty twenty-five." ``` See [Prompting tips](/build-with-cartesia/capability-guides/prompting-tips) for the written forms Sonic normalizes today, and pre-normalization as a fallback for edge cases. Documentation for configuring individual normalizers is coming soon. ### Regional reading conventions Today, `en-GB` and `en-US` produce identical normalization output: English and Hindi are excluded from the locale-aware normalization engine, so all English regional variants inherit the same reading conventions. The `locale` and `normalization` fields make regional differentiation expressible. If British-specific read-outs matter for your product today, pre-normalize the forms that differ (dates, currency) and see [turning normalization off](#turning-normalization-off). ### Turning normalization off Setting `normalization` to `"off"` skips the automatic normalizer — and only the automatic normalizer. Everything else still applies: * [SSML tags](/build-with-cartesia/capability-guides/ssml-tags) and [generation controls](/build-with-cartesia/capability-guides/volume-speed-emotion) * [Pronunciation dictionaries](/build-with-cartesia/capability-guides/custom-pronunciations) * Transcript buffering * Input validation: potentially malicious character sequences may be blocked for security and stability reasons Turn it off when you pre-normalize text yourself, need a custom read-out for a symbol (for example, `#` as "number"), or need all-caps words spoken as words rather than spelled out letter by letter. Normalization is all-or-nothing per request — there is no per-span control. If most of a transcript should be normalized but one span shouldn't, write out that span as it should be spoken (along with any other written forms in the transcript that would have needed normalizing) and send the request with normalization off. ### Normalizer worked examples #### Pre-normalized text with the normalizer off For "teleprompter" transcripts you've already written out the way they should be spoken, custom symbol read-outs, or all-caps words that should be spoken as words: ```json theme={null} { "model_id": "sonic-preview", "transcript": "Your total is nineteen dollars and ninety-nine cents.", "voice": "a0e99841-438c-4a64-b679-ae501e7d6091", "locale": "en", "normalization": "off", "output_format": { "container": "mp3", "sample_rate": 44100, "bit_rate": 128000 } } ``` Only the automatic normalizer is skipped — see [turning normalization off](#turning-normalization-off) for exactly what still applies. #### British accent with US reading conventions The decoupling pattern itself: pick the accent with `locale`, pick the reading conventions with `normalization`. ```json theme={null} { "model_id": "sonic-preview", "transcript": "Your appointment is on 03/04/2026.", "voice": "62ae83ad-4f6a-430b-af41-a9bede9286ca", "locale": "en-GB", "normalization": "en-US", "output_format": { "container": "mp3", "sample_rate": 44100, "bit_rate": 128000 } } ``` This reads with a British accent and US conventions (`03/04/2026` as March fourth). Note that today the reverse isn't distinguishable — see [regional reading conventions](#regional-reading-conventions): `en-GB` and `en-US` normalization output is currently identical, so this pattern matters as regional differentiation lands rather than changing read-outs today. #### Different read-out conventions inside one transcript A single request applies one `normalization` value to the whole transcript — there is no per-span control, because detecting language switches inside a transcript would add latency to every request. If one clause needs Hindi read-outs and another needs English read-outs, split the transcript and send two requests with different `normalization` values and the **same voice**, so the accent stays consistent, then concatenate the audio: ```json Request 1 theme={null} { "model_id": "sonic-preview", "transcript": "Aapki appointment 15 tareekh ko hai.", "voice": "a0e99841-438c-4a64-b679-ae501e7d6091", "locale": "hi-IN", "normalization": "hi-IN", "output_format": { "container": "raw", "encoding": "pcm_s16le", "sample_rate": 44100 } } ``` ```json Request 2 theme={null} { "model_id": "sonic-preview", "transcript": "Please arrive by 2:30 PM on 08/15/2026.", "voice": "a0e99841-438c-4a64-b679-ae501e7d6091", "locale": "hi-IN", "normalization": "en-IN", "output_format": { "container": "raw", "encoding": "pcm_s16le", "sample_rate": 44100 } } ``` On the [WebSocket API](/api-reference/tts/websocket), raw PCM chunks from consecutive generations can be concatenated directly. # Choosing a Voice Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/choosing-a-voice How to pick the best voice for your Voice Agents When designing a voice agent experience, the voice that you choose plays a critical role in making the agent experience pleasant, natural, and understandable for your users. Cartesia offers 500+ voices out-out-of-box, as well as the ability to clone your own voices. ### Featured Voices Featured voices are a handpicked set of Voices that our Voices team believes to be great voices. We make this determination through a combination of usage, performance, robust internal evaluations, and customer feedback. These voices are a great starting point to find the best voice for your voice agent. Featured Voices are displayed with a check mark icon next to their names on our [Voice Library](https://play.cartesia.ai/voices) page. ### Stable voices (best for voice agents) For voice agents in production, we've found that more stable, realistic voices perform better than studio quality, emotive voices. From our testing, we think these are the top performing English Voices for voice agents: * **Male**: Archie, Ronald, Carson, Jameson, Daniel * **Female**: Skylar, Gemma, Katie, Jacqueline, Cathy, Caroline ### Emotive voices (best for AI characters) Sonic is expressive with some voices like Tessa and Maya labeled as emotive in the playground, and respond well to [emotion instructions](/build-with-cartesia/capability-guides/volume-speed-emotion). If your use case requires more expressive speech (e.g. companion apps, game characters), then we suggest trying: * **Male**: Kyle, Cory, Nolan * **Female**: Tessa, Ariana, Lucy We tag such voices as Emotive in our playground and you can see a full list [here](https://play.cartesia.ai/voices?tags=Emotive). If you have your own audio recordings for AI characters or emotive voices, we would suggest using our [Professional Voice Cloning](/build-with-cartesia/capability-guides/clone-voices-pro) feature to train a model specific to them. ## Creating a Voice If you can't find a voice that suits your needs, you can easily create your own custom voices. This can be done from audio samples or from a base voice. We offer two methods of creating voices - [Instant Clones](/build-with-cartesia/capability-guides/clone-voices) and [Professional Voice Clones](/build-with-cartesia/capability-guides/clone-voices-pro). ## Sharing a voice Voices you create are private to your Cartesia organization by default. To use a custom voice on a third-party platform, share the voice first. * **In the dashboard**: open the [My Voices tab](https://play.cartesia.ai/voices?category=my-voices), use the three-dots menu next to a voice, and select **Share**. * **Via the API**: call the [Update Voice API](/api-reference/voices/update) and set `access.type` to `public`. Set it back to `private` to stop sharing. To see which voices are currently shared, call the [List Voices API](/api-reference/voices/list) with `is_owner=true` and look for voices with `access.type` set to `public`. # Instant Voice Clone Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/clone-voices Learn how to get the best voice clones from your audio clips Instant Voice cloning is available through the [playground](https://play.cartesia.ai) and the [API](/api-reference/voices/clone). You'll be asked to provide a clip that lasts up to 10 seconds, of which you can either record directly or upload a file. In the playground, you also choose the clip's language and accent. Training instant clones is fast and free. For the best voice clones, we recommend following these best practices: ## General best practices for voice cloning 1. **Choose an appropriate script to speak.** You want your recording to align as closely as possible with the voice you want to generate. For example, don't read a colorless transcript in a monotone voice unless you're aiming for a monotonous clone. Instead, prepare a script that is suited to your use case and has the right energy. 2. **Speak as clearly as possible and avoid background noise.** For example, when recording yourself, try to use a high-quality microphone and be in a quiet space. 3. **Avoid long pauses.** Pauses in the recording will be mimicked by the cloned voice, such as between sentences. Ensure your recording matches the pacing you want your voice to follow. 4. **Trim your recording.** The audio you provide should roughly contain speech from start to finish. Make sure the speaker is not cut-off and that there's no excessive silence at the beginning or end. You can use a tool like Audacity or our playground make the perfect clip from your recording. 5. **Speak in the target language.** For instance, if you want the cloned voice to speak Spanish, speak Spanish in the recording. If this is not possible, you can use Cartesia's localization feature—available in the playground and in the API—to convert your clone to a different language. # Pro Voice Clone Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/clone-voices-pro Create a near-exact voice replica, trained on 30+ minutes of your audio A Professional Voice Clone (PVC) fine-tunes a Cartesia text-to-speech (TTS) model on your audio to produce a near-exact replica of a voice: its accent, speaking style, and audio quality. We recommend starting with an [Instant Voice Clone](/build-with-cartesia/capability-guides/clone-voices) because it's fast and high quality for most use cases. Use a PVC when the IVC isn't a close enough match and you can supply 30+ minutes of studio-quality audio of a single speaker. | Feature | Required audio data | Subscription plan needed | | ------------------- | ------------------- | ------------------------ | | Instant Voice Clone | 10 seconds | Pro plan or above | | Pro Voice Clone | 30 minutes | Startup plan or above | ## Create a PVC A PVC closely matches the audio you train it on. Use clean recordings of a single speaker at the volume, pacing, and audio quality you want. The more you provide, the better: 30 minutes is the minimum, and 2 hours or more gives the best results. Training then takes up to 3 hours. **Speed and volume are fixed.** A PVC learns pacing and loudness from your dataset, so the [speed and volume controls](/build-with-cartesia/capability-guides/volume-speed-emotion) have no effect at request time. Set the speed and volume you want in your source audio before training. You can create a PVC from the Cartesia dashboard or the API. ### In the dashboard Open the [Pro Voice Clone](https://play.cartesia.ai/pro-voice-cloning) page. From here you create a PVC and track the status of your existing clones. Follow the steps on screen to provide audio data, start the training, and listen to the voices it creates. ### With the API Create PVCs programmatically using the following endpoints: 1. [Create a dataset](/api-reference/datasets/create) to hold your data 2. [Upload files](/api-reference/datasets/upload-file) to the dataset 3. [Create a fine-tune](/api-reference/fine-tunes/create) from the dataset 4. [List the voices](/api-reference/fine-tunes/list-voices) the fine-tune produced > **Prerequisites** > > 1. You have a **Cartesia API key** (export it as `CARTESIA_API_KEY`). > 2. You have a folder called `samples/` with one or more `.wav` files. ```python expandable theme={null} """ End-to-end Pro Voice Cloning example. Steps ----- 1. Create a dataset. 2. Upload audio files from samples/ to the dataset. 3. Kick off a fine-tune from that dataset. 4. Poll until fine-tune is completed. 5. Get the voices produced by the fine-tune. """ import os import time from pathlib import Path import requests API_BASE = "https://api.cartesia.ai" API_HEADERS = { "Cartesia-Version": "2026-08-14", "Authorization": f"Bearer {os.environ['CARTESIA_API_KEY']}", } MODEL_ID = "sonic-3.5-2026-05-04" def create_dataset(name: str, description: str) -> str: """POST /datasets → dataset id.""" res = requests.post( f"{API_BASE}/datasets", headers=API_HEADERS, json={"name": name, "description": description}, ) res.raise_for_status() return res.json()["id"] def upload_file_to_dataset(dataset_id: str, path: Path) -> None: """POST /datasets/{dataset_id}/files (multipart/form-data).""" with path.open("rb") as fp: res = requests.post( f"{API_BASE}/datasets/{dataset_id}/files", headers=API_HEADERS, files={"file": fp, "purpose": (None, "fine_tune")}, ) res.raise_for_status() def create_fine_tune(dataset_id: str, *, name: str, language: str, model_id: str) -> str: """POST /fine-tunes → fine-tune id.""" body = { "name": name, "description": "Pro Voice Clone demo", "language": language, "model_id": model_id, "dataset": dataset_id, } res = requests.post(f"{API_BASE}/fine-tunes", headers=API_HEADERS, json=body, timeout=60) res.raise_for_status() return res.json()["id"] def wait_for_fine_tune(ft_id: str, every: float = 10.0) -> None: """Poll GET /fine-tunes/{id} until status == completed.""" start = time.monotonic() while True: res = requests.get(f"{API_BASE}/fine-tunes/{ft_id}", headers=API_HEADERS) res.raise_for_status() status = res.json()["status"] print(f"fine-tune {ft_id} -> {status}. Elapsed: {time.monotonic() - start:.0f}s") if status == "completed": return if status == "failed": raise RuntimeError(f"fine-tune ended with status={status}") time.sleep(every) def list_voices(ft_id: str) -> list[dict]: """GET /fine-tunes/{id}/voices → list of voices.""" res = requests.get(f"{API_BASE}/fine-tunes/{ft_id}/voices", headers=API_HEADERS) res.raise_for_status() return res.json()["data"] if __name__ == "__main__": # Create the dataset DATASET_ID = create_dataset("PVC demo", "Samples for a Pro Voice Clone") print("Created dataset:", DATASET_ID) # Upload .wav files to the dataset for wav_path in Path("samples").glob("*.wav"): upload_file_to_dataset(DATASET_ID, wav_path) print(f"Uploaded {wav_path.name} to dataset {DATASET_ID}") # Kick off the fine-tune FINE_TUNE_ID = create_fine_tune( DATASET_ID, name="PVC demo", language="en", model_id=MODEL_ID, ) print(f"Started fine-tune: {FINE_TUNE_ID}") # Wait for training to finish wait_for_fine_tune(FINE_TUNE_ID) print("Fine-tune completed!") # Fetch the voices created by the fine-tune voices = list_voices(FINE_TUNE_ID) print("Voices IDs:") for voice in voices: print(voice["id"]) ``` ## Use a PVC in Text-to-Speech A Pro Voice Clone starts out supported on the TTS model it was trained on. As Cartesia releases newer models, we automatically make your voice available on them, so it keeps working when you upgrade. In your text-to-speech API request, set [`model_id`](/api-reference/tts/bytes#body-model-id) to one of the voice's supported models, returned in the [`fine_tunes.public_model_id`](/api-reference/voices/get#response-fine-tunes-items-public-model-id) field of the [Get Voice](/api-reference/voices/get) response. Passing an unsupported `model_id` returns HTTP `400` with a `voice_model_mismatch` error: ```json theme={null} { "error_code": "voice_model_mismatch", "title": "Invalid voice", "message": "The requested voice is not compatible with the requested model. Switch to one of these compatible models: sonic-3.5-2026-05-04.", "request_id": "550e8400-e29b-41d4-a716-446655440000" } ``` ## FAQs For most use cases, start with an IVC: it's fast, high quality, and needs only 10 seconds of audio. Choose a PVC to clone character voices, preserve rare accents, or match a specific tone and pacing. Find your PVCs from the Cartesia dashboard or the API. In the dashboard, go to [My Voices](https://play.cartesia.ai/voices?category=my-voices) in the Voice Library and look for the **PRO** badge. From the API, call [List Voices](/api-reference/voices/list) with `is_owner=true` and filter for voices where `is_pro=true`. The number of PVC fine tunes you can create depends on your subscription plan: | Plan | PVC slots | | ---------- | ------------- | | Free | Not available | | Pro | Not available | | Startup | 2 | | Scale | 4 | | Enterprise | Custom | To find how many PVC fine tunes you currently have, open the [Pro Voice Clone](https://play.cartesia.ai/pro-voice-cloning) page in the dashboard. The **Limit** line shows how many fine tunes you've created against your plan's total. Your existing PVCs keep working. To train a new one, delete a fine-tune you no longer need from the [Pro Voice Clone](https://play.cartesia.ai/pro-voice-cloning) page or the [Delete Fine Tune](/api-reference/fine-tunes/delete) endpoint, or upgrade your plan for more slots. Slots aren't sold separately. To make room for a new PVC, free up a slot by deleting a fine-tune you no longer need, or upgrade your plan for more slots. Your existing PVCs keep working, even if you're over your new plan's limit. You can't train a new one until you're back under the limit. No. We automatically adapt your PVC to new TTS models as they're released, so it keeps working when you switch `model_id`. These adapted versions don't count against your plan's slots. # Custom Pronunciations Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/custom-pronunciations Specify custom pronunciations for words that are hard to get right, like proper nouns or domain-specific terms. Pronunciation dictionaries let you specify how to pronounce specific words and phrases. A dictionary is a simple search and replace, which directs the model to use another string in lieu of the text from the transcript. The pronunciation can be either an [IPA pronunciation](/build-with-cartesia/capability-guides/phonemes) or a "sounds-like" guidance: ```json lines theme={null} [ { "text": "bayou", "pronunciation": "<<ˈ|b|ɑ|ˈ|j|u>>" }, { "text": "jambalaya", "pronunciation": "<<ˈ|dʒ|ə|m|ˈ|b|ə|ˈ|l|aɪ|ˈ|ə>>" }, { "text": "tchoupitoulas", "pronunciation": "chop-uh-TOO-liss" } ] ``` Save these JSONs as pronunciation dictionaries [through our API](/api-reference/pronunciation-dicts/create) or through our [playground](https://play.cartesia.ai/pronunciation): image.png Once a dictionary is created, use it in any TTS API by passing its id as `pronunciation_dict_id`. With the dictionary above, the string `I ate some jambalaya on tchoupitoulas street` becomes `I ate some <<ˈ|dʒ|ə|m|ˈ|b|ə|ˈ|l|aɪ|ˈ|ə>> on chop-uh-TOO-liss street` before being handed off to the model. ## Case Sensitivity Dictionary matching is **case-sensitive**, with one exception: a lowercase entry also matches its sentence-start capitalized form. For example, `cat` matches both `cat` and `Cat`, but not `CAT`. An entry for `CAT` only matches `CAT`. This applies to multi-word entries too. An entry for `green valley` matches `green valley` and `Green valley`, but not `Green Valley`. **Use lowercase entries for common words.** These match the word both mid-sentence (`cat`) and at the start of a sentence (`Cat`), covering the two most common positions. **Use exact capitalization for proper nouns.** A term like `LaTeX` should be entered as `LaTeX` so it doesn't collide with a different pronunciation for the common word `latex`. For multi-word proper nouns, enter the exact casing as it appears in your transcripts, for example `Green Valley` if the transcript capitalizes both words. ## Sharing a dictionary New dictionaries are private by default, so only your organization can use them. To use this pronunciation dictionary for Text-to-Speech generation in an external account, set its access to public. * **In the dashboard**: open the [Pronunciation tab](https://play.cartesia.ai/pronunciation), use the three-dots menu next to a dictionary, and select **Share**. * **Via the API**: call the [Update Pronunciation Dictionary API](/api-reference/pronunciation-dicts/update) and set `access.type` to `public`. Set it back to `private` to stop sharing. To see which dictionaries are currently shared, call the [List Pronunciation Dictionaries API](/api-reference/pronunciation-dicts/list) and look for entries with `access.type` set to `public`. # Multilingual Voices Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/multilingual-voices Make a voice sound native in new languages and accents. A voice can support one or more locales, defined by language and accent. A voice may sound less natural when used in a locale it does not support. For example, an American English voice used to generate Spanish will speak with an American accent. ## Localization **Localization** adapts a voice to sound natural in a target locale while preserving the original speaker’s identity and character. You can localize a voice to a different language, such as adapting an English voice to Spanish, or to a different accent, such as adapting an American English voice to British English. Localization is available in the [playground](https://play.cartesia.ai/voices/create/localize) and the [API](/api-reference/voices/localize). Provide the source voice, its gender, and the target language and accent. See the [API reference](/api-reference/voices/localize) for the full list of supported locales. Localization currently creates a new voice with its own `voice_id`. We’re working to let you add more locales to an existing voice instead. Localization works with voices in the [Voice Library](https://play.cartesia.ai/voices) and [Instant Voice Clones](/build-with-cartesia/capability-guides/clone-voices). It isn't supported for [Pro Voice Clones](/build-with-cartesia/capability-guides/clone-voices-pro). ## Voices that support multiple locales Some featured voices support multiple locales through a single `voice_id`. Find the supported locales of a voice via the [Get Voice API](/api-reference/voices/get#response-locales). Set the `language` field to the locale you want the voice to speak. If you omit it, Cartesia will attempt to detect the language from the transcript. For more reliable language detection, avoid very short transcripts. ### Code-switching For best results, use a single language per generation — for example, send separate API calls for "For English, press one" and "Para Español, marque dos". **Code-switching** — using two languages in the same generation — works for languages where it's common, such as Hindi (Hinglish) and Tagalog (Taglish). Outside of those, code-switching may result in accented speech in one of the languages. # Prompting tips Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/prompting-tips Get natural-sounding output from Sonic with minimal prompt engineering. Sonic 3.5 is designed to sound natural with minimal prompt engineering. In most cases you can pass your transcript as-is and let the model handle normalization, pacing, and expression. The tips below apply across the Sonic family; differences between Sonic 3.5 and Sonic 3 are called out inline. ## Recommendations * **Pass natural, well-punctuated text.** Full sentences with normal capitalization and punctuation produce the best pacing and intonation. End each transcript with terminal punctuation (`.`, `?`, `!`). * **Send complete phrases.** Full sentences sound more natural than isolated fragments or single words. Don't send a number, code, or spell tag on its own — include the surrounding sentence, e.g. `Your confirmation code is ABC123.` * **Use normal casing.** Reserve all-caps for acronyms you want read out letter by letter (e.g. `USA`). Other all-caps words may be misread as initialisms (e.g. `NASA`). Avoid using capitalization for emphasis or to indicate shouting. * **Pass numbers, currency, dates, and common acronyms in conventional written form.** Sonic maps these patterns to natural speech for most inputs: * Large numbers like `1,234,567` * Currency like `$19.99` * US phone numbers: `(415) 555-1212` * Street addresses like `123 Main St` * Email addresses: `user@example.com` * Dates in `MM/DD/YYYY`: `04/20/2025` * Times with a space before AM/PM: `7:00 PM`, `7 PM`, `7:00 P.M.` * Common acronyms (`NASA`) and initialisms (`USA`) Symbols are handled naturally — `@` reads as `at` (email addresses), `()` is silent (for US phone numbers). When an LLM writes the transcript, see [**Voice agents (LLM-authored text)**](#voice-agents-llm-authored-text). * **Match the voice to the language.** Each voice has a primary language it works best with. Use the [Playground](https://play.cartesia.ai) to audition voices for a given language. * **Keep prompts in their natural written form.** Heavy preprocessing (stripping punctuation, forcing casing) generally hurts output quality. ## Pre-normalization Sonic 3.5 automatically covers the common cases above for most inputs. If you hit an unusual case or a bug where something is still misread, you may consider pre-normalizing your text as a fallback. Have your LLM write the transcript fully spelled out, the way it would be spoken. | Written | Spoken (fully normalized) | | ----------- | ------------------------------------------------ | | `$123.50` | one hundred twenty-three dollars and fifty cents | | `Dr. Smith` | Doctor Smith | | `14:30` | two thirty PM | Pre-normalizing is a fallback for edge cases. Well-punctuated text in conventional form is read correctly in the large majority of cases. ## Controlling pacing and spelling When you need character-by-character read-out (confirmation codes, order IDs, serial numbers, spelled-out names) or fine-grained pacing, use one of the following: 1. **Spell tags (recommended).** Wrap the string in `...`. Most reliable option, works for letters, digits, and mixed alphanumerics in all supported languages. ``` Your confirmation code is AB12CD. ``` 2. **Space-delimited characters.** Alternatively, you can achieve the same result by separating characters with single spaces for a natural spelling pace. ``` Your code is A B C 1 2 3. ``` 3. **Comma-delimited characters.** If your use case requires longer pauses, you can add a comma and a space after each character. ``` Your code is A, B, C, 1, 2, 3. ``` 4. **Semantic grouping.** For more natural pacing, use spaces and add commas where a human would naturally pause. ``` Your code is A B C, 1 2 3. ``` **Migrating from Sonic 3?** The recommended delimiter format has changed in Sonic 3.5. Separate characters with **spaces or commas** and put a comma between groups. Don't put periods between characters or mix commas and periods, this format still works on `sonic-3` snapshots but is not recommended for Sonic 3.5. | Scenario | Old (Sonic 3) | New (Sonic 3.5) | | ------------------------------ | ---------------------- | --------------------- | | Spell out letters `HELLO` | `H. E. L. L. O.` | `H E L L O` | | Spell out digits `123456` | `1. 2. 3. 4. 5. 6.` | `1 2 3 4 5 6` | | Confirmation code `ABC123` | `A, B, C. 1, 2, 3.` | `A B C, 1 2 3` | | Slow, digit-by-digit `266AO48` | `2. 6. 6. A. O. 4. 8.` | `2, 6, 6, A, O, 4, 8` | ## Voice agents (LLM-authored text) **Starter system prompt.** Baseline you can paste and trim for your product. If your stack **does not** pass `` or other tags through to Sonic, omit the tag lines and use the delimiter fallback in section 4. ```text theme={null} You are a voice agent. Everything you output will be spoken aloud by Cartesia Sonic text-to-speech. Follow these rules: 1. GENERAL FORMATTING - Write plain prose in full sentences. Always end with . ? or ! - Send complete phrases, not isolated words or fragments. Keep numbers, codes, and spell tags inside a surrounding sentence. - Do NOT use markdown, bullet points, headers, bold, raw JSON, emoji, or special characters. Sonic reads them aloud as written. 2. CAPITALIZATION - Use normal capitalization, exactly as the sentence would normally be written: capitalize the first word, proper nouns, and the word I, and lowercase everything else. This is the default for almost all output. - The model tends to read an all-caps token letter by letter. Use all-caps only when you want that, like an initialism you want spelled out (USA, FBI, ATM). - Do not put ordinary words in all-caps. They may be misread as initialisms and spelled out letter by letter. - Common acronyms normally said as a word, like NASA or NATO, work in their standard form. If one is read the wrong way, force the reading with tags or rephrase. - Do not use capitalization for emphasis or to indicate shouting. It changes how a word is read, not how loud it sounds. 3. NUMBERS, DATES, AND SYMBOLS - Use conventional written forms and let text normalization speak them. No preprocessing needed: numbers like 1,234,567; currency like $19.99; percentages like 12%; dates like 04/20/2025; times like 7:00 PM; US phone numbers like (415) 555-1212; addresses like 123 Main St; emails like user@example.com. - Do not strip punctuation or force casing. Heavy preprocessing may hurt output quality. 4. SPELLING OUT CODES AND IDS - For confirmation codes, reference numbers, or any alphanumeric ID that must be read character by character, wrap it in tags: Example: Your confirmation code is TKT4829XB. - Alternatively, delimit the characters instead: spaces (A B C 1 2 3) for a natural pace, or commas (A, B, C, 1, 2, 3) to slow it down. Do not put periods between sequences of individual characters. - For long sequences like credit card numbers, break the run into smaller comma-separated groups the way a person reads them aloud (3 6 8 9, 0 5 0 5, 2 5 8 2, 3 6 7 9). - NATO phonetics (Alpha, Bravo) help when the listener needs to disambiguate letters. 5. PAUSES - Use natural punctuation for pauses. A comma or period usually produces the right pause in context. - For an explicit, fixed-duration silence, use a break tag: Example: Your balance is $1,234. Your next payment is due June 15th. - Avoid placing several break tags in quick succession, which can cause hallucinations, and do not chain and tags. 6. SPEED (beta) - To slow down speech generation, use a speed tag with a ratio between 0.6 and 1.5: - Return to normal speed after: 7. THINGS TO AVOID - Do not output bullet points, numbered lists, or any structured formatting. Speak items naturally with pauses between them, and do not say "here's a list." - Do not use asterisks, hashtags, or markdown syntax. Do not wrap words in **bold** or *italics* — the engine will speak the asterisks. - Do not improvise details that were not provided. - Do not repeat the same information more than once unless asked. ``` ## Inserting pauses Use natural punctuation for pauses — a comma or period usually produces the right pause in context. For an explicit, fixed-duration silence, use a [break tag](/build-with-cartesia/capability-guides/ssml-tags#pauses-and-breaks). Break tags split the generation, so they can sound less natural; avoid placing several in quick succession, which can cause hallucinations. Each tag counts as a single character and doesn't need surrounding whitespace. ## Disfluencies Documentation for disfluencies is coming soon. ## Pronunciation For proper nouns, trademarks, and domain-specific terms — or to disambiguate identical spellings (e.g. *Nice*, the city, vs. *nice*, the adjective) — use [custom pronunciations](/build-with-cartesia/capability-guides/custom-pronunciations). ## Streaming Use [continuations](/build-with-cartesia/capability-guides/stream-inputs-using-continuations) when generating chunks of audio that need to sound contiguous (for example, LLM-streamed output). This preserves prosody and voice consistency across chunk boundaries. # SSML Tags Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/ssml-tags Laughter, pauses, and mid-transcript controls Tags for volume, speed, and emotions are in beta and subject to change in the future. Sonic supports SSML-like (Speech Synthesis Markup Language) tags to control generated speech. The supported tags are `speed`, `volume`, `emotion`, `break`, and `spell`. ## Speed *Available on `sonic-3` and `sonic-3.5`.* Note that if you're streaming token by token, you'll need to buffer the whole value of the speed or volume tags. Passing in `1`, `.`, `0` as separate inputs, for example, will result in reading out the tags. You can guide the speed of a TTS generation with a `speed` tag, which takes a scalar between `0.6` and `1.5`. This value is roughly a multiplier on the default speed. For example, `1.5` will generate audio at roughly 1.5x the default speed. ```xml theme={null} I like to speak quickly because it makes me sound smart. ``` ## Volume *Available on `sonic-3` and `sonic-3.5`.* You can guide the volume of a TTS generation with a `volume` tag, which is a number between `0.5` and `2.0`. The default volume is `1`. ```xml theme={null} I will speak softly. ``` ## Emotion Beta Emotion control is highly experimental, particularly when emotion shifts occur mid-generation. If you need to change the emotion in a transcript, we recommend using separate generation contexts for each emotion. For best results, use [Voices tagged as "Emotive"](https://play.cartesia.ai/voices?tags=Emotive), as emotions may not work reliably with other Voices. ```xml theme={null} I will not allow you to continue this! I was hoping for a peaceful resolution. ``` ## Pauses and breaks Punctuation is the first tool for pausing — a comma or period usually produces a natural, well-paced pause in context. Reserve `break` tags for when you need an explicit silence of a specific duration. A `break` tag takes one attribute, `time`, in seconds (`s`) or milliseconds (`ms`): ```xml theme={null} Hello, my name is Sonic.Nice to meet you. ``` Break tags split the generation, so the model has less surrounding context and the speech can sound less natural. Avoid placing several break tags in quick succession, which can cause the model to hallucinate. Each tag counts as 1 character and doesn't need surrounding whitespace. ## Spelling out numbers and letters To read input out character by character, wrap it in `` tags. This is useful for confirmation codes, order IDs, serial numbers, or spelling a name. ```xml theme={null} My name is Bob, spelled Bob, and my confirmation code is ABC123. ``` The model adds a slight pause between runs of letters and digits automatically. To force a longer pause at a specific point, add a space inside the tag: ```xml theme={null} Your confirmation code is ABC 123. ``` Avoid other punctuation inside `` tags — it may be read aloud (for example, a period is read as "dot"). For phone numbers, credit card numbers, and similar sequences, write them as a plain string and let [text normalization](/build-with-cartesia/capability-guides/prompting-tips#recommendations) handle the grouping and pacing. Reach for a `` tag only when you need a strict character-by-character read-out, and don't chain `` and `` tags. # Stream Inputs using Continuations Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/stream-inputs-using-continuations Learn how to stream input text to Sonic TTS In many real-time use cases, you don't have input text available upfront—like when you're generating it on the fly using a language model. For these cases, we support input streaming through a feature we call *continuations*. This guide will cover how input streaming works from the perspective of the TTS model. If you just want to implement input streaming, see [the WebSocket API reference](/api-reference/tts/websocket), which implements continuations using *contexts*. The Python and TypeScript SDKs handle the `continue` flag for you: `ctx.push()` sends each chunk with `continue: true`, and `ctx.no_more_inputs()` sends `continue: false`. See the [WebSocket continuations example](/examples/tts-websocket-continuations) for working code. ## Continuations Continuations are generations that extend already generated speech. They're called continuations because you're continuing the generation from where the last one left off, maintaining the *prosody* of the previous generation. If you don't use continuations, you get sudden changes in prosody that create seams in the audio. Prosody refers to the rhythm, intonation, and stress in speech. It's what makes speech flow naturally and sound human-like. Let's say we're using an LLM and it generates a transcript in three parts, with a one second delay between each part: 1. `Hello, my name is Sonic.` 2. ` It's very nice` 3. ` to meet you.` To generate speech for the whole transcript, we might think to generate speech for each part independently and stitch the audios together: no_continuations Unfortunately, we end up with speech that has sudden changes in prosody and strange pacing: Your browser does not support the audio element. Now, let's try the same transcripts, but using continuations. The setup looks like this: continuations Here's what we get: Your browser does not support the audio element. As you can hear, this output sounds seamless and natural. You can scale up continuations to any number of inputs. There is no limit. ## Caveat: Streamed inputs should form a valid transcript when joined This means that `"Hello, world!"` can be followed by `" How are you?"` (note the leading space) but not `"How are you?"`, since when joined they form the invalid transcript `"Hello, world!How are you?"`. In practice, this means you should maintain spacing and punctuation in your streamed inputs. **End complete sentences with closing punctuation** (for example `.`, `?`, or `!`). If a streamed chunk does not end with sentence-ending punctuation, the model often treats it as an incomplete sentence. That can cause: * **Extra latency:** Text may stay in the automatic input buffer until the model sees a clearer boundary or until `max_buffer_delay_ms` elapses (**3000ms by default**), so audio starts later than you expect. * **Audio artifacts:** The model expects natural sentence endings; without closing punctuation, the generated audio sometimes ends with odd or distorted sounds. When a user-facing utterance is finished, put terminal punctuation on the final segment (and signal that no more text is coming on the context when appropriate, for example `no_more_inputs()` in the SDK or `continue: false` over the WebSocket). ## Automatic buffering with `max_buffer_delay_ms` When streaming inputs from LLMs word-by-word or token-by-token, we buffer text until the optimal transcript length for our model. The default buffer is 3000ms, if you wish to modify this you can use the `max_buffer_delay_ms` parameter, though we *do not recommend making this change*. If you plan on using `speed` or `volume` [SSML tags](/build-with-cartesia/capability-guides/ssml-tags) with buffering, make sure decimal values are not split up. Submitting `1.0` as `1`, `.`, `0` will result in unintended failure modes. ### How it works When set, the model will buffer incoming text chunks until it's confident it has enough context to generate high-quality speech, or the buffer delay elapses, whichever comes first. Without this buffer, the model would immediately start generating with each input, which could result in choppy audio or unnatural prosody if inputs are very small (like single words or tokens). ### Configuration * **Range**: Values between 0-5000ms are supported * **Default**: 3000ms Use this *only* if * you have custom buffering client side, in which case you can set this to 0 * you have choppiness even at 3000ms, in which case you can try a higher value ```js lines theme={null} // Example WebSocket request with `max_buffer_delay_ms` { "model_id": "sonic-3.5", "transcript": "Hello", // First word/token "voice": "a0e99841-438c-4a64-b679-ae501e7d6091", "context_id": "my-conversation-123", "continue": true, "max_buffer_delay_ms": 3000 // Buffer up to 3000ms } ``` Let's try the following transcripts with continuations and the default `max_buffer_delay_ms=3000`: `['Hello', 'my name', 'is Sonic.', "It's ", 'very ', 'nice ', 'to ', 'meet ', 'you.']` Your browser does not support the audio element. ## Where to go next # Text Normalization Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/text-normalization How written text becomes spoken text, and what to do when something reads out wrong. Text normalization converts written forms into spoken forms: `7:00 PM` is spoken as "seven PM", and `(415) 555-1212` is read as a phone number rather than a twelve-digit string. It runs automatically on every TTS request before the model speaks. You control it with the `normalization` field: * `auto` (default) — Cartesia decides how dates, times, and numbers are read * `off` — skip the normalizer * a locale code such as `en-IN` — read dates and numbers the Indian English way. See [supported locales](/build-with-cartesia/tts-models/preview#languages-and-locales). Locale codes work on Sonic 3.6 (`sonic-preview`). On Sonic 3.5 they return 400. English and Hindi currently read the same way — see [regional reading conventions](/build-with-cartesia/capability-guides/advanced-capabilities#regional-reading-conventions). Most transcripts need no preparation. This page covers what the normalizer handles, its current limitations and their workarounds, and how to turn it off. ## What gets normalized | Category | Example input | Status | | ------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------- | | Dates | `04/20/2026` | Common written forms are automatically normalized | | Times | `7:00 PM`, `14:30` | Common written forms are automatically normalized | | Phone numbers | `(415) 555-1212` | Common written forms are automatically normalized | | Currency | `$19.99` | Common written forms are automatically normalized | | Units | `km` | Units with everyday usage are automatically normalized | | Numbers | `1,234,567` | Common written forms are automatically normalized | | Date ranges | `1999-2000` | Not normalized — [write the range with "to"](#a-date-or-year-range-reads-out-wrong) | | Fractions | `2/3` | Not normalized — write them out ("two thirds") | | Other | Equations, chemical compounds, uncommon units (e.g. V, Pa) | Not normalized — write them out ("volts, pascals") | **Normalized** categories are locale-aware and read according to the conventions of the request's language. **Common written forms** read correctly in the formats shown on [prompting tips](/build-with-cartesia/capability-guides/prompting-tips#recommendations); for unusual forms, [pre-normalize](/build-with-cartesia/capability-guides/prompting-tips#pre-normalization) as a fallback. 24-hour times are read as-is in the language's convention — `14:30` in an English transcript reads as "fourteen thirty". ## Known limitations ### A date or year range reads out wrong Hyphenated ranges like `1999-2000` or `Dec 5-Dec 12` are not automatically normalized in any language. Write the range with "to" instead: | Unreliable | Reliable | | -------------------------------- | ----------------------------------- | | `The war lasted from 1999-2000.` | `The war lasted from 1999 to 2000.` | | `Open Dec 5-Dec 12.` | `Open Dec 5 to Dec 12.` | ### Industry-specific Terms Some industries may have common abbreviations that are mutually understandable within that group (`PAX` = passengers for airlines). Because these abbreviations are not generally used, we recomend pre-normalizing these terms to ensure that they are spoken as expected. ### Abbreviations Common patterns (`Dr. Smith`, `123 Main St`) generally read correctly. Less common titles, abbreviations, and address formats may not (e.g. `STE` — write the specific form out as it should be spoken, or use a [pronunciation dictionary](/build-with-cartesia/capability-guides/custom-pronunciations) for a recurring term. ## Turning normalization off See [turning normalization off](/build-with-cartesia/capability-guides/advanced-capabilities#turning-normalization-off) in Advanced capabilities. ## Troubleshooting a read-out problem 1. **Right words, wrong sounds?** That's model pronunciation, not normalization. Use a [pronunciation dictionary](/build-with-cartesia/capability-guides/custom-pronunciations). 2. **A written form expands into the wrong words?** That's normalization. Rewrite the input in a form the normalizer handles — see [known limitations](#known-limitations) for the common cases, like writing ranges with "to". 3. **Still wrong?** Pre-normalize the transcript and [turn normalization off](#turning-normalization-off). This gives you full control of the spoken form. For transcript-writing guidance, see [prompting tips](/build-with-cartesia/capability-guides/prompting-tips). # Build with Sonic Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/tts The quickest way to get started with Sonic is by using an [integration](/integrations/overview). If you are using the API directly, check out Cartesia's [client libraries](/tools/client-libraries) and [AI tools](/tools/ai/agent-guide). The references section contains complete documentation for all API endpoints and best practices. Build a voice agent Skills for coding agents The official Cartesia SDKs Simple scripts using Sonic ## References # Caching Audio for Stock Responses Source: https://docs.cartesia.ai/build-with-cartesia/capability-guides/tts-caching Pre-generate stock TTS phrases as raw PCM, then interleave them with live WebSocket audio to cut latency and credits ## Goal Stock phrases (greetings, hold messages, sign-offs) repeat across calls. Regenerating them every time adds latency and costs credits. Instead, pre-generate those phrases once as raw PCM, cache them, and splice them into a live TTS stream at runtime. Cached clips skip the API, so those segments are faster and free. You can also check out the video tutorial: