Migration guides / Fish Audio
Move your Fish Audio TTS API to Cartesia
Cartesia reads the model and the voice from the JSON body, where Fish Audio splits them between a request header and reference_id.
Why migrate from Fish Audio now
Dated changes on the Fish Audio side, each linked to the page that announces it.
S1 retires
Fish Audio lists s1 as deprecated. Requests that send model: s1 need a new model before the end of the year either way.
Migrate from Fish Audio with your coding agent
Paste this into Claude Code, Cursor or Codex in the repo that calls Fish Audio. It carries the field mapping, the Cartesia request and a rollout that keeps Fish Audio behind a flag until you switch.
Prompt
Move this codebase from Fish Audio to Cartesia for text to speech. Keep Fish Audio working behind a flag until I switch over.
December 31, 2026: S1 retires. Fish Audio lists `s1` as deprecated. Requests that send `model: s1` need a new model before the end of the year either way. (https://docs.fish.audio/developer-guide/models-pricing/models-overview)
## 1. Find the calls
Search for `api.fish.audio` or `FISH_API_KEY`. The request to replace is `POST https://api.fish.audio/v1/tts`. 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: Fish Audio sends the key in `Authorization: Bearer` token from `FISH_API_KEY`. Replace it with `X-API-Key` from `CARTESIA_API_KEY` on the Cartesia path only, and keep `FISH_API_KEY` for the Fish Audio path. Fish Audio shows a new key once, on its developer page. Copy it before you close the dialog.
- Add `CARTESIA_API_KEY` wherever the project documents its environment (`.env.example`, README, deploy config). Never hardcode the key.
- Concurrency: Fish Audio allows 5 concurrent requests under $100 paid, 15 from $100, 50 from $1,000. 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 Fish Audio 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: Expressive narrator for video content → `a33f7a4c-100f-41cf-a1fd-5822e8fc253f` (Lauren - Lively Narrator); Upbeat promo or ad read → `710feaa3-b550-42f3-b3eb-6f37f2a7cc0a` (Tanner - Upbeat Assistant); Friendly in-game companion → `6ccbfb76-1fc6-48f7-b71d-91ac6298247b` (Tessa - Kind Companion); Slow, calm long-form read → `98a34ef2-2140-4c28-9c71-663dc4dd7022` (Clyde - Calm Narrator).
## 3. Field mapping, Fish Audio → Cartesia
- `POST https://api.fish.audio/v1/tts` → `POST /tts/bytes`
- `Authorization: Bearer $FISH_API_KEY` → `X-API-Key` and `Cartesia-Version: 2026-08-14`
- `model` header: `s2.1-pro`, `s2-pro`, `s1` or `drama-3` → `model_id`: `sonic-3.6` in the body
- `text` → `transcript`
- `reference_id` → `voice`: `{"id": "<voice id>"}`. Fish Audio voice models don't export. Pick a library voice or clone the source recording.
- `format`: `wav`, `pcm` or `mp3` → `output_format`: `container` `wav`, `raw` or `mp3`. Fish Audio's `pcm` is 16-bit mono. Set `raw` with `pcm_s16le` to match it.
- `sample_rate` → `output_format.sample_rate`
- `mp3_bitrate`: 64, 128 or 192 → `output_format.bit_rate`: 32000 to 192000. Cartesia counts bits per second, so 128 becomes 128000.
- `prosody.speed` (0.5 to 2.0) → `generation_config.speed` (0.6 to 1.5). Cap anything under 0.6 or over 1.5 at the nearest end.
- `prosody.volume` (decibels) → `generation_config.volume` (0.5 to 2.0). Cartesia uses a multiplier, not decibels. Match loudness by listening.
- Emotion tags in the text, `[happy]` on S2 or `(happy)` on S1 → `generation_config.emotion`, or an `emotion` tag in the transcript. Cartesia accepts a fixed list of emotions. Free-form cues such as `[whispers sweetly]` need rewording.
- `pronunciation_dictionary` (up to 3) → `pronunciation_dict_id` (one dictionary). Merge your dictionaries into one before uploading.
## 4. Fish Audio fields with no Cartesia equivalent
- `references`: inline audio and transcript, MessagePack only. What to do: Clone the clip once with `client.voices.clone(clip=..., language=..., name=...)` and reuse the ID.
- `format`: `opus`. What to do: Request `mp3` or raw PCM and transcode to Opus.
- `latency`, `chunk_length`, `temperature`, `top_p`. What to do: Drop them.
- `<|speaker:0|>` multi-speaker tags. What to do: Send each speaker's lines as their own request and join the audio.
## 5. 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 = "Your character reached level ten. A new quest is waiting at the harbor."
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)
```
## 6. Roll out
1. Choose Fish Audio or Cartesia per request from one config flag, defaulting to Fish Audio.
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 Fish Audio 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
- Fish Audio text-to-speech API reference: https://docs.fish.audio/api-reference/endpoint/openapi-v1/text-to-speech
- Fish Audio quickstart: https://docs.fish.audio/developer-guide/getting-started/quickstart
- Fish Audio voice cloning best practices: https://docs.fish.audio/developer-guide/best-practices/voice-cloning
- Fish Audio emotion tags: https://docs.fish.audio/developer-guide/core-features/emotions
- Cartesia TTS bytes API reference: https://docs.cartesia.ai/api-reference/tts/bytes
- Cartesia SSML tags: https://docs.cartesia.ai/build-with-cartesia/capability-guides/ssml-tags
When you're done, tell me which files changed, which fields you couldn't map, and how to flip the flag.Every Fish Audio field, mapped to Cartesia
The prompt carries this table. Each row is a field in your Fish Audio request and the Cartesia field that replaces it.
- Fish Audio
POST https:// api.fish.audio/ v1/ tts CartesiaPOST /tts/bytes - Fish Audio
Authorization: Bearer $FISH_API_KEYCartesiaX-API-KeyandCartesia-Version: 2026-08-14 - Fish Audio
modelheader:s2.1-pro,s2-pro,s1ordrama-3Cartesiamodel_id:sonic-3.6in the body - Fish Audio
textCartesiatranscript - Fish Audio
reference_idCartesiavoice:{"id": "<voice id>"}NoteFish Audio voice models don't export. Pick a library voice or clone the source recording. - Fish Audio
format:wav,pcmormp3Cartesiaoutput_format:containerwav,rawormp3NoteFish Audio'spcmis 16-bit mono. Setrawwithpcm_s16leto match it. - Fish Audio
sample_rateCartesiaoutput_format.sample_rate - Fish Audio
mp3_bitrate: 64, 128 or 192Cartesiaoutput_format.bit_rate: 32000 to 192000NoteCartesia counts bits per second, so 128 becomes 128000. - Fish Audio
prosody.speed(0.5 to 2.0)Cartesiageneration_config.speed(0.6 to 1.5)NoteCap anything under 0.6 or over 1.5 at the nearest end. - Fish Audio
prosody.volume(decibels)Cartesiageneration_config.volume(0.5 to 2.0)NoteCartesia uses a multiplier, not decibels. Match loudness by listening. - Fish Audio
Emotion tags in the text,
[happy]on S2 or(happy)on S1Cartesiageneration_config.emotion, or anemotiontag in the transcriptNoteCartesia accepts a fixed list of emotions. Free-form cues such as[whispers sweetly]need rewording. - Fish Audio
pronunciation_dictionary(up to 3)Cartesiapronunciation_dict_id(one dictionary)NoteMerge your dictionaries into one before uploading.
Fish Audio 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.
- Fish Audio
Authorization: BearertokenCartesiaX-API-KeyplusCartesia-Version: 2026-08-14NoteFish Audio shows a new key once, on its developer page. Copy it before you close the dialog. - Fish Audio
FISH_API_KEYCartesiaCARTESIA_API_KEY
Fish Audio 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
s2.1-pro, s2-pro and s1
Fish Audio$0.015Note$15 per million UTF-8 bytes. English text is one byte per character; Chinese, Japanese and Korean are three. - Model or plan
s2.1-pro-free
Fish Audio$0NoteFair-use limits, no latency guarantee - Model or plan
drama-3
Fish Audio$0.05Note$50 per million bytes; $10 promotional price until November 12, 2026
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.
Fish Audio 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)Fish AudioNo API credit for new accounts;s2.1-pro-freecosts nothing under fair-use limits - Limit
Languages
Cartesia44 languages for text to speechFish Audio83 languages on S2.1-Pro
Cartesia's figures come from its pricing page and voice library.
Cartesia pricing and plan limitsSources
Limits read from each company's documentation in November 2026.
Fish Audio voices and where to start on Cartesia
Voice models chosen by reference_id, from the public library or your own clones
Each card is a starting point for a common Fish Audio pick, matched by language and use. Listen before you choose.
What you get on Cartesia
What changes once the Fish Audio call is gone.
Billed per character, not per byte
Fish Audio meters text in UTF-8 bytes, so each Chinese, Japanese or Korean character counts as three. Cartesia charges 1 credit per character.
Clone once, then send an ID
Fish Audio's inline references carry audio inside each request and require MessagePack. On Cartesia you upload a clip once, from 10 seconds, and every TTS call stays plain JSON with a voice ID.
How to migrate from Fish Audio to Cartesia
The same changes the prompt makes, if you'd rather make them yourself.
Create a Cartesia API key and store it next to
FISH_API_KEY.For each
reference_idyou call, pick a library voice by role, or clone the original recording. Fish Audio asks for at least 10 seconds of audio, which is also Cartesia's instant-clone minimum.Move the model from the header into
model_id, renametexttotranscriptand nest the format fields underoutput_format.Rewrite bracketed emotion cues as Cartesia emotions, and split multi-speaker scripts into one request per speaker.
Ship behind a flag for a share of traffic and compare the same lines on both before you drop the Fish Audio path.
Sources
Request shapes checked against vendor documentation in November 2026.
Compare and read next
Frequently asked questions
Where do I get a Fish Audio API key, and what replaces it?
Fish Audio creates the key in one click on its developer page and shows it once; its docs read it from FISH_API_KEY and send it as a Bearer token. On Cartesia, create a key in the dashboard, keep it in CARTESIA_API_KEY, and send it as X-API-Key with a Cartesia-Version header.
Is the Fish Audio API free?
Partly. New API accounts start with no credit, and paid models return 402 until you add some. The s2.1-pro-free model costs nothing under fair-use limits, with no latency guarantee. Fish Audio's consumer plans are billed separately from the API.
Can I bring my Fish Audio voice to Cartesia?
Not the reference_id. Clone the original recording, if you have it and permission to use it: Cartesia's instant clone takes 10 seconds of audio on a Pro plan or higher, and Sonic 3.6 learns from up to 60 seconds.
What doesn't carry over from Fish Audio?
Free-form bracket cues, multi-speaker tags, Opus output and the latency, chunk_length, temperature and top_p controls. Speed narrows to 0.6 to 1.5, and you get one pronunciation dictionary per request where Fish Audio takes three.
How do I move traffic over without a big switch?
Wrap both request builders behind one function and route by a percentage flag. Start with the voices that have the closest Cartesia match, log which vendor rendered each line, and set the flag back to zero for any voice that players report.
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.