Migration guides / Inworld TTS
Migrate Inworld TTS to Cartesia
Port each Inworld TTS API call to a Cartesia request that takes a plain key header and returns the audio as bytes.
What happened to Inworld TTS
The dated events that ended the Inworld TTS API, each linked to its source.
inworld-tts-1 and inworld-tts-1-max discontinued
Inworld now sends requests for both ids to newer models, so audio you tuned on TTS 1 or TTS 1 Max now comes from a model you never tested. Inworld also marks inworld-tts-1.5-max and inworld-tts-1.5-mini as deprecated, with no end date.
Migrate from Inworld TTS with your coding agent
Paste this into Claude Code, Cursor or Codex in the repo that calls Inworld TTS. It carries the field mapping, the Cartesia request and a rollout that keeps Inworld TTS behind a flag until you switch.
Prompt
Move this codebase from Inworld TTS to Cartesia for text to speech. Keep Inworld TTS working behind a flag until I switch over.
June 15, 2026: `inworld-tts-1` and `inworld-tts-1-max` discontinued. Inworld now sends requests for both ids to newer models, so audio you tuned on TTS 1 or TTS 1 Max now comes from a model you never tested. Inworld also marks `inworld-tts-1.5-max` and `inworld-tts-1.5-mini` as deprecated, with no end date. (https://docs.inworld.ai/tts/tts-models)
## 1. Find the calls
Search for `api.inworld.ai` or `INWORLD_API_KEY`. The request to replace is `POST https://api.inworld.ai/tts/v1/voice`. List every call site before you edit anything.
## 2. Target
- Request: `POST https://api.cartesia.ai/tts/bytes`
- Model: `model_id: "sonic-3.6"`
- Headers: `X-API-Key` read from the `CARTESIA_API_KEY` environment variable, and `Cartesia-Version: 2026-08-14`
- Auth swap: Inworld TTS sends the key in `Authorization: Basic <base64 key_id:secret>` from `INWORLD_API_KEY`. Replace it with `X-API-Key` from `CARTESIA_API_KEY` on the Cartesia path only, and keep `INWORLD_API_KEY` for the Inworld TTS path. Inworld's portal copies the credential already Base64-encoded, so it goes in as is. Cartesia keys need no encoding.
- Add `CARTESIA_API_KEY` wherever the project documents its environment (`.env.example`, README, deploy config). Never hardcode the key.
- Request size: Inworld TTS caps a request at 2,000 characters on the synthesize endpoint; 4,000 on HTTP streaming. Cartesia publishes no per-request maximum, so keep any chunking the code already does and split at sentence boundaries; for long text, stream over the Cartesia TTS WebSocket.
- Concurrency: Inworld TTS allows 5 concurrent requests on On-Demand, 10 on Creator, 50 on Builder, 150 on Developer, 500 on Growth. Look up the Cartesia plan's concurrent request limit at https://www.cartesia.ai/pricing, cap parallel requests at it, and retry rate-limit errors with backoff.
- Voice IDs don't carry over. Keep each voice ID in one named constant or config value, put a placeholder where each Inworld TTS voice was, and list them for me so I can pick replacements at https://www.cartesia.ai/voices.
- Suggested starting points to put in those placeholders, for me to confirm by ear: A warm voice for a companion or social app → `ec1e269e-9ca0-402f-8a18-58e0e022355a` (Ariana - Kind Friend); A deep voice for a guard, villain or other game character → `6a176356-ada1-4b48-b2ae-3a3fdd485680` (Elias - Night Warden); A narrator or oracle with gravitas for quests and cutscenes → `d7862948-75c3-4c7c-ae28-2959fe166f49` (Caspian - Oracle); A tutor or language partner → `f9fc912e-52f0-448a-8bfa-47e9ca75f25a` (Marilyn - Explainer).
## 3. Field mapping, Inworld TTS → Cartesia
- `POST https://api.inworld.ai/tts/v1/voice` → `POST https://api.cartesia.ai/tts/bytes`
- `Authorization: Basic <base64 key_id:secret>` → `X-API-Key` and `Cartesia-Version: 2026-08-14`
- `text`, up to 2,000 characters (4,000 on HTTP streaming) → `transcript`
- `modelId`: `inworld-tts-2`, `inworld-tts-2-flash`, or a deprecated `inworld-tts-1.5-max` or `inworld-tts-1.5-mini` → `model_id`: `sonic-3.6`. Inworld now routes `inworld-tts-1` and `inworld-tts-1-max` to newer models, so code that still names them is already running on a different model.
- `voiceId`, such as `Ashley` → `voice`: `{"id": "<voice id>"}`
- `language` (BCP-47) → `language`: `en` or `en-GB`
- `audioConfig.audioEncoding`: `LINEAR16` → `output_format`: `wav` container, `pcm_s16le`. Inworld's `LINEAR16` carries a WAV header, so `wav` is the match. Cartesia outputs `wav`, `mp3` and `raw` PCM only, so transcode for Opus or anything else.
- `audioConfig.sampleRateHertz` → `output_format.sample_rate`
- `audioConfig.speakingRate` (0.5 to 1.5) → `generation_config.speed` (0.6 to 1.5). Cartesia's floor is 0.6, so send 0.6 for any Inworld rate below it.
- `timestampType`: `WORD` or `CHARACTER` → `add_timestamps` on the TTS WebSocket. Word timestamps arrive as WebSocket events, and `/tts/bytes` returns none. Character timings and visemes have no equivalent.
- `pronunciationDictionarySettings` → `pronunciation_dict_id`. One dictionary per request, on `sonic-3` and newer.
- Response `audioContent` (base64) → Response body is the audio bytes
## 4. Reference request
Match the language and HTTP client the codebase already uses. This is the same request in Python:
```python
import os
import requests
text = "Stay close, traveler. The bridge ahead won't hold us both."
VOICE_ID = "6ccbfb76-1fc6-48f7-b71d-91ac6298247b" # from /voices
response = requests.post(
"https://api.cartesia.ai/tts/bytes",
headers={
"X-API-Key": os.environ["CARTESIA_API_KEY"],
"Cartesia-Version": "2026-08-14",
},
json={
"model_id": "sonic-3.6",
"transcript": text,
"voice": {"id": VOICE_ID},
"language": "en",
"output_format": {
"container": "wav",
"encoding": "pcm_s16le",
"sample_rate": 44100,
},
},
)
response.raise_for_status()
open("out.wav", "wb").write(response.content)
```
## 5. Roll out
1. Choose Inworld TTS or Cartesia per request from one config flag, defaulting to Inworld TTS.
2. Run the same scripts through both and save the clips side by side for me to listen to. Check that the container, encoding and sample rate match what downstream code expects.
3. Leave the Inworld TTS client, call and key in place so rollback is flipping the flag. Don't delete them in this change.
4. Run the existing tests, and add one that checks the Cartesia request body.
## Docs
- Inworld synthesize speech reference: https://docs.inworld.ai/api-reference/ttsAPI/texttospeech/synthesize-speech
- Inworld TTS models: https://docs.inworld.ai/tts/tts-models
- Inworld API key authentication: https://docs.inworld.ai/portal/api-key-auth
- Cartesia TTS bytes API reference: https://docs.cartesia.ai/api-reference/tts/bytes
When you're done, tell me which files changed, which fields you couldn't map, and how to flip the flag.Every Inworld TTS field, mapped to Cartesia
The prompt carries this table. Each row is a field in your Inworld TTS request and the Cartesia field that replaces it.
- Inworld TTS
POST https:// api.inworld.ai/ tts/ v1/ voice CartesiaPOST https:// api.cartesia.ai/ tts/ bytes - Inworld TTS
Authorization: Basic <base64 key_id:secret>CartesiaX-API-KeyandCartesia-Version: 2026-08-14 - Inworld TTS
text, up to 2,000 characters (4,000 on HTTP streaming)Cartesiatranscript - Inworld TTS
modelId:inworld-tts-2,inworld-tts-2-flash, or a deprecatedinworld-tts-1.5-maxorinworld-tts-1.5-miniCartesiamodel_id:sonic-3.6NoteInworld now routesinworld-tts-1andinworld-tts-1-maxto newer models, so code that still names them is already running on a different model. - Inworld TTS
voiceId, such asAshleyCartesiavoice:{"id": "<voice id>"} - Inworld TTS
language(BCP-47)Cartesialanguage:enoren-GB - Inworld TTS
audioConfig.audioEncoding:LINEAR16Cartesiaoutput_format:wavcontainer,pcm_s16leNoteInworld'sLINEAR16carries a WAV header, sowavis the match. Cartesia outputswav,mp3andrawPCM only, so transcode for Opus or anything else. - Inworld TTS
audioConfig.sampleRateHertzCartesiaoutput_format.sample_rate - Inworld TTS
audioConfig.speakingRate(0.5 to 1.5)Cartesiageneration_config.speed(0.6 to 1.5)NoteCartesia's floor is 0.6, so send 0.6 for any Inworld rate below it. - Inworld TTS
timestampType:WORDorCHARACTERCartesiaadd_timestampson the TTS WebSocketNoteWord timestamps arrive as WebSocket events, and/tts/bytesreturns none. Character timings and visemes have no equivalent. - Inworld TTS
pronunciationDictionarySettingsCartesiapronunciation_dict_idNoteOne dictionary per request, onsonic-3and newer. - Inworld TTS
Response
audioContent(base64)CartesiaResponse body is the audio bytes
Inworld TTS API key and auth, mapped to Cartesia
Cartesia reads the key from the X-API-Key header and pins the API version with Cartesia-Version on every request.
- Inworld TTS
Authorization: Basic <base64 key_id:secret>CartesiaX-API-KeyplusCartesia-Version: 2026-08-14NoteInworld's portal copies the credential already Base64-encoded, so it goes in as is. Cartesia keys need no encoding. - Inworld TTS
INWORLD_API_KEYCartesiaCARTESIA_API_KEY
Inworld TTS API pricing per 1,000 characters
List prices per 1,000 characters from the vendor's own pricing page. Plans, regions and volume discounts change what you pay.
- Model or plan
TTS-2 on On-Demand (no monthly fee)
Inworld TTS$0.025 - Model or plan
TTS-2 on Growth ($1,500 a month)
Inworld TTS$0.0125NoteInworld's lowest self-serve TTS-2 rate - Model or plan
TTS-2 Flash on On-Demand
Inworld TTS$0.015 - Model or plan
TTS-2 Flash on Growth
Inworld TTS$0.007
On Cartesia, usage draws from your plan's credits: 20,000 credits a month on the Free plan (about 20,000 characters). Enterprise pricing is custom.
Cartesia plans and pricingSources
Prices read from each company's pricing page in November 2026.
Inworld TTS limits compared with Cartesia
Published limits from both companies. Plans change them, so check both pages before you size a rollout.
- Limit
Free tier
Cartesia20,000 credits a month on the Free plan (about 20,000 characters)Inworld TTSUp to 70 minutes of TTS free on On-Demand, which has no monthly fee - Limit
Request limit
CartesiaNo published maximum; stream long text over the TTS WebSocketInworld TTS2,000 characters on the synthesize endpoint; 4,000 on HTTP streaming - Limit
Languages
Cartesia44 languages for text to speechInworld TTS200+ languages and locales on TTS-2 and TTS-2 Flash
Cartesia's figures come from its pricing page and voice library.
Cartesia pricing and plan limitsSources
- Inworld billingdocs.inworld.ai
- Inworld pricinginworld.ai
- Inworld synthesize speech referencedocs.inworld.ai
- Inworld TTS modelsdocs.inworld.ai
Limits read from each company's documentation in November 2026.
Inworld TTS voices and where to start on Cartesia
Inworld AI voices are built-in names such as Ashley or Dennis, plus the clones and designed voices in your workspace.
Each card is a starting point for a common Inworld TTS pick, matched by language and use. Listen before you choose.
What you get on Cartesia
What changes once the Inworld TTS call is gone.
The key goes in as issued
X-API-Key takes the key exactly as Cartesia shows it, with no key_id:secret pair to encode.
The response is the audio file
Write the response body straight to disk. The audioContent decode step goes away.
How to migrate from Inworld TTS to Cartesia
The same changes the prompt makes, if you'd rather make them yourself.
Make a Cartesia API key and store it beside your Inworld credential while both run.
Cast a voice for each character or persona in the voice library. Inworld voice IDs have no Cartesia equivalent.
Swap the request, delete the base64 decode, and move your pronunciation overrides into a Cartesia pronunciation dictionary.
Render the same lines on both vendors and compare them before you shift traffic.
Sources
Request shapes checked against vendor documentation in November 2026.
Compare and read next
Frequently asked questions
Is Inworld TTS free?
Up to a point. The On-Demand plan has no monthly fee and includes up to 70 minutes of TTS, then bills $25 per million characters for TTS-2. Cartesia's Free plan renews 20,000 credits every month, about 20,000 characters.
How does Inworld AI pricing work?
Each plan's monthly fee comes back as usage credit, from $0 on On-Demand to $1,500 on Growth, and each step up lowers the per-character rate. Unused credit rolls over for 3 months. Enterprise rates start at $5 per million characters for TTS-2, by contract.
Does the auth scheme change?
Yes. Inworld reads a Basic authorization header. Cartesia reads an X-API-Key header plus a required Cartesia-Version header.
How do I stream audio while it is generated?
Open the TTS WebSocket, documented in the TTS API reference.
Does Cartesia cover the same languages?
No. Inworld lists more than 200 languages and locales for TTS-2, and Sonic speaks 44. Check Cartesia's list against the languages your characters speak.
What doesn't carry over?
Character-level timestamps, visemes, speaking rates below 0.6, and any language outside Sonic's 44. Word timestamps survive on the WebSocket only.
Can I move one character at a time?
Yes. Choose the TTS vendor per character with a config flag, move a few characters to Cartesia, and set the flag back if players or testers object to a voice. Both APIs keep no state between requests, so rollback needs no data migration.
Get started today
Talk to an expert.
Connect with a member of our team and learn how Cartesia can help you build world-class voice experiences.
Start building.
Create an API key, then hand your coding agent the migration prompt and a few of your own scripts.