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.

Inworld TTS models

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.

12 fields mapped, with a rollback plan

Prompt

Connect MCP
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.

  1. Inworld TTS

    POST https://api.inworld.ai/tts/v1/voice

    Cartesia
    POST https://api.cartesia.ai/tts/bytes
  2. Inworld TTS

    Authorization: Basic <base64 key_id:secret>

    Cartesia
    X-API-Key and Cartesia-Version: 2026-08-14
  3. Inworld TTS

    text, up to 2,000 characters (4,000 on HTTP streaming)

    Cartesia
    transcript
  4. Inworld TTS

    modelId: inworld-tts-2, inworld-tts-2-flash, or a deprecated inworld-tts-1.5-max or inworld-tts-1.5-mini

    Cartesia
    model_id: sonic-3.6
    Note
    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.
  5. Inworld TTS

    voiceId, such as Ashley

    Cartesia
    voice: {"id": "<voice id>"}
  6. Inworld TTS

    language (BCP-47)

    Cartesia
    language: en or en-GB
  7. Inworld TTS

    audioConfig.audioEncoding: LINEAR16

    Cartesia
    output_format: wav container, pcm_s16le
    Note
    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.
  8. Inworld TTS

    audioConfig.sampleRateHertz

    Cartesia
    output_format.sample_rate
  9. Inworld TTS

    audioConfig.speakingRate (0.5 to 1.5)

    Cartesia
    generation_config.speed (0.6 to 1.5)
    Note
    Cartesia's floor is 0.6, so send 0.6 for any Inworld rate below it.
  10. Inworld TTS

    timestampType: WORD or CHARACTER

    Cartesia
    add_timestamps on the TTS WebSocket
    Note
    Word timestamps arrive as WebSocket events, and /tts/bytes returns none. Character timings and visemes have no equivalent.
  11. Inworld TTS

    pronunciationDictionarySettings

    Cartesia
    pronunciation_dict_id
    Note
    One dictionary per request, on sonic-3 and newer.
  12. Inworld TTS

    Response audioContent (base64)

    Cartesia
    Response 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.

  1. Inworld TTS

    Authorization: Basic <base64 key_id:secret>

    Cartesia
    X-API-Key plus Cartesia-Version: 2026-08-14
    Note
    Inworld's portal copies the credential already Base64-encoded, so it goes in as is. Cartesia keys need no encoding.
  2. Inworld TTS

    INWORLD_API_KEY

    Cartesia
    CARTESIA_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.

  1. Model or plan

    TTS-2 on On-Demand (no monthly fee)

    Inworld TTS
    $0.025
  2. Model or plan

    TTS-2 on Growth ($1,500 a month)

    Inworld TTS
    $0.0125
    Note
    Inworld's lowest self-serve TTS-2 rate
  3. Model or plan

    TTS-2 Flash on On-Demand

    Inworld TTS
    $0.015
  4. 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 pricing

Sources

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.

  1. Limit

    Free tier

    Cartesia
    20,000 credits a month on the Free plan (about 20,000 characters)
    Inworld TTS
    Up to 70 minutes of TTS free on On-Demand, which has no monthly fee
  2. Limit

    Request limit

    Cartesia
    No published maximum; stream long text over the TTS WebSocket
    Inworld TTS
    2,000 characters on the synthesize endpoint; 4,000 on HTTP streaming
  3. Limit

    Languages

    Cartesia
    44 languages for text to speech
    Inworld TTS
    200+ 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 limits

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.

  1. Make a Cartesia API key and store it beside your Inworld credential while both run.

  2. Cast a voice for each character or persona in the voice library. Inworld voice IDs have no Cartesia equivalent.

  3. Swap the request, delete the base64 decode, and move your pronunciation overrides into a Cartesia pronunciation dictionary.

  4. Render the same lines on both vendors and compare them before you shift traffic.

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.

Contact Sales

Start building.

Create an API key, then hand your coding agent the migration prompt and a few of your own scripts.

Try Cartesia