Cartesia Text-to-Speech Skill
Ultra-low latency TTS via Cartesia Sonic-3. ~90ms first-byte streaming, 40+ languages, 60+ emotion controls.
Capabilities
| Feature | Endpoint | Latency | Use Case |
|---|---|---|---|
| Batch TTS | POST /tts/bytes |
Full generation | Audio file creation, offline processing |
| SSE Streaming | POST /tts/sse |
Medium | HTTP streaming, simpler than WebSocket |
| WebSocket Streaming | wss://api.cartesia.ai/tts/websocket |
~90ms first byte | Real-time conversations, Pipecat, telephony |
| Voice Library | GET /voices |
N/A | List and browse available voices |
Authentication
All requests require a Cartesia API key:
export CARTESIA_API_KEY="your-api-key"
REST header: X-API-Key: $CARTESIA_API_KEY (or Authorization: Bearer $CARTESIA_API_KEY)
Cartesia-Version header: Cartesia-Version: 2024-06-10
WebSocket: Pass as query param ?api_key=$CARTESIA_API_KEY&cartesia_version=2024-06-10
Batch TTS (Bytes Endpoint)
Endpoint: POST https://api.cartesia.ai/tts/bytes
Returns complete audio file. Best for generating audio files, batch processing, offline use.
Generate MP3
curl -s -X POST "https://api.cartesia.ai/tts/bytes" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" \
-H "Content-Type: application/json" \
-d '{
"model_id": "sonic",
"transcript": "Hello, this is a test of Cartesia text to speech.",
"voice": {"mode": "id", "id": "81db94f2-ea76-4e5a-94bf-c92be997270d"},
"output_format": {"container": "mp3", "bit_rate": 128000, "sample_rate": 44100}
}' -o output.mp3
Generate WAV
curl -s -X POST "https://api.cartesia.ai/tts/bytes" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" \
-H "Content-Type: application/json" \
-d '{
"model_id": "sonic",
"transcript": "Hello, this is a test.",
"voice": {"mode": "id", "id": "81db94f2-ea76-4e5a-94bf-c92be997270d"},
"output_format": {"container": "wav", "encoding": "pcm_s16le", "sample_rate": 44100}
}' -o output.wav
Generate Raw PCM (for streaming pipelines)
curl -s -X POST "https://api.cartesia.ai/tts/bytes" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" \
-H "Content-Type: application/json" \
-d '{
"model_id": "sonic",
"transcript": "Raw PCM for pipeline processing.",
"voice": {"mode": "id", "id": "81db94f2-ea76-4e5a-94bf-c92be997270d"},
"output_format": {"container": "raw", "encoding": "pcm_f32le", "sample_rate": 24000}
}' -o output.raw
Multilingual TTS
curl -s -X POST "https://api.cartesia.ai/tts/bytes" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" \
-H "Content-Type: application/json" \
-d '{
"model_id": "sonic-multilingual",
"transcript": "Bonjour, ceci est un test en français.",
"voice": {"mode": "id", "id": "81db94f2-ea76-4e5a-94bf-c92be997270d"},
"language": "fr",
"output_format": {"container": "mp3", "bit_rate": 128000, "sample_rate": 44100}
}' -o output_fr.mp3
Model Selection
| Model ID | Description | Latency | Languages | Best For |
|---|---|---|---|---|
sonic-3 |
Latest, most emotive | ~90ms | 40+ | Production conversational AI |
sonic-2024-12-12 |
Dated version of Sonic | ~100ms | 20+ | Pinned deployments |
sonic-multilingual |
Multilingual variant | ~100ms | 20+ | Non-English content |
sonic-turbo |
Speed-optimized | ~80ms | 20+ | Ultra-low latency needed |
sonic |
Original/alias | ~120ms | 20+ | General purpose |
Recommendation: Use sonic or sonic-3 for most use cases.
Output Format Options
Container Formats
| Container | Description | Use Case |
|---|---|---|
raw |
Raw PCM bytes | Streaming pipelines, Pipecat, lowest latency |
wav |
WAV file with headers | File storage, batch processing |
mp3 |
Compressed MP3 | Web delivery, playback, storage |
Encoding Options (for raw and wav)
| Encoding | Bit Depth | Description |
|---|---|---|
pcm_s16le |
16-bit signed | Standard quality, telephony compatible |
pcm_f32le |
32-bit float | Higher quality, larger size |
pcm_mulaw |
8-bit μ-law | Twilio/telephony (8kHz) |
pcm_alaw |
8-bit A-law | European telephony |
Sample Rates
| Rate | Use Case |
|---|---|
8000 |
Telephony (Twilio mulaw) |
16000 |
Wideband telephony |
22050 |
Standard streaming |
24000 |
High quality streaming, Pipecat default |
44100 |
CD quality, file output |
Voice Selection
List Available Voices
curl -s "https://api.cartesia.ai/voices" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" | jq '[.[] | select(.language == "en") | {id, name}][:10]'
Voice Specification
{
"voice": {
"mode": "id",
"id": "81db94f2-ea76-4e5a-94bf-c92be997270d"
}
}
Notable English Voices
| Voice ID | Name | Style |
|---|---|---|
81db94f2-ea76-4e5a-94bf-c92be997270d |
Jeff | General purpose male |
17ab4eb9-ef77-4a31-85c5-0603e9fce546 |
Matt | Male |
1998363b-e108-4736-bc5b-1449fa2b096a |
Aditi | Female |
4d2fd738-3b3d-4368-957a-bb4805275bd9 |
British Narration Lady | Narration |
69267136-1bdc-412f-ad78-0caad210fb40 |
Friendly Reading Man | Conversational |
5345cf08-6f37-424d-a5d9-8ae1101b9377 |
Maria | Female |
Browse all voices: https://play.cartesia.ai/voices
WebSocket Streaming
Endpoint: wss://api.cartesia.ai/tts/websocket
Best for real-time conversational AI, voice assistants, Pipecat pipelines.
Python Example
import asyncio
import websockets
import json
import base64
import os
async def stream_tts():
"""Stream TTS audio via Cartesia WebSocket."""
api_key = os.environ["CARTESIA_API_KEY"]
url = f"wss://api.cartesia.ai/tts/websocket?api_key={api_key}&cartesia_version=2024-06-10"
async with websockets.connect(url) as ws:
# Send generation request
request = {
"model_id": "sonic",
"transcript": "Hello! This is streaming text to speech from Cartesia.",
"voice": {"mode": "id", "id": "81db94f2-ea76-4e5a-94bf-c92be997270d"},
"context_id": "my-context",
"output_format": {
"container": "raw",
"encoding": "pcm_s16le",
"sample_rate": 24000
},
"add_timestamps": True
}
await ws.send(json.dumps(request))
# Receive audio chunks
audio_chunks = []
async for msg in ws:
data = json.loads(msg)
if data.get("type") == "chunk":
audio_bytes = base64.b64decode(data["data"])
audio_chunks.append(audio_bytes)
elif data.get("type") == "timestamps":
words = data["word_timestamps"]["words"]
print(f"Words: {words}")
elif data.get("type") == "done":
print("Generation complete")
break
elif data.get("type") == "error":
print(f"Error: {data['error']}")
break
# Combine all chunks
full_audio = b"".join(audio_chunks)
print(f"Total audio: {len(full_audio)} bytes")
return full_audio
asyncio.run(stream_tts())
WebSocket Messages
Send — Generation Request:
{
"model_id": "sonic",
"transcript": "Text to speak",
"voice": {"mode": "id", "id": "voice-id"},
"context_id": "unique-context-id",
"output_format": {"container": "raw", "encoding": "pcm_s16le", "sample_rate": 24000},
"add_timestamps": true,
"continue": false
}
Send — Cancel:
{"context_id": "unique-context-id", "cancel": true}
Receive — Audio Chunk:
{"type": "chunk", "data": "base64_pcm_audio", "done": false, "status_code": 206, "step_time": 45, "context_id": "..."}
Receive — Timestamps:
{"type": "timestamps", "word_timestamps": {"words": ["Hello", "world"], "start": [0.0, 0.5], "end": [0.4, 0.9]}, "context_id": "..."}
Receive — Done:
{"type": "done", "done": true, "status_code": 206, "context_id": "..."}
Pipecat Integration
For voice AI pipelines using Pipecat with Cartesia TTS:
from pipecat.services.cartesia import CartesiaTTSService
from pipecat.services.deepgram import DeepgramSTTService
from pipecat.pipeline.pipeline import Pipeline
# Create TTS service for Pipecat pipeline
tts = CartesiaTTSService(
api_key=os.environ["CARTESIA_API_KEY"],
voice_id="81db94f2-ea76-4e5a-94bf-c92be997270d", # Jeff
model="sonic",
sample_rate=24000,
encoding="pcm_s16le",
container="raw",
)
# Create STT service
stt = DeepgramSTTService(
api_key=os.environ["DEEPGRAM_API_KEY"],
params=DeepgramSTTService.InputParams(
model="nova-3",
language="en",
smart_format=True,
endpointing=300,
interim_results=True,
)
)
# Full pipeline: Audio In → STT → LLM → TTS → Audio Out
pipeline = Pipeline([
transport.input(),
stt,
llm,
tts,
transport.output(),
])
Pipecat with Emotion Control (Sonic-3)
from pipecat.services.cartesia import CartesiaTTSService
tts = CartesiaTTSService(
api_key=os.environ["CARTESIA_API_KEY"],
voice_id="voice-id",
model="sonic-3",
params=CartesiaTTSService.InputParams(
language="en",
speed=1.0,
emotion=["excited"],
)
)
Twilio Telephony + Pipecat + Cartesia
# For phone calls via Twilio SIP → Pipecat → Cartesia TTS
# Use mulaw encoding at 8kHz for telephony
tts = CartesiaTTSService(
api_key=os.environ["CARTESIA_API_KEY"],
voice_id="voice-id",
model="sonic",
sample_rate=8000,
encoding="pcm_mulaw",
container="raw",
)
Request Parameters Reference
Core Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
model_id |
string | Yes | Model to use (sonic, sonic-3, sonic-multilingual, etc.) |
transcript |
string | Yes | Text to synthesize |
voice |
object | Yes | {"mode": "id", "id": "voice-uuid"} |
output_format |
object | Yes | Container, encoding, sample_rate (see above) |
language |
string | No | ISO language code (auto-detected if omitted) |
Generation Config (Sonic-3)
| Parameter | Type | Range | Default | Description |
|---|---|---|---|---|
generation_config.volume |
float | 0.5–2.0 | 1.0 | Output volume |
generation_config.speed |
float | 0.6–1.5 | 1.0 | Speech rate |
generation_config.emotion |
string | See list | neutral | Emotion control |
Streaming Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
context_id |
string | — | Groups related requests for multi-turn |
continue |
bool | false | Continue previous context |
add_timestamps |
bool | false | Return word-level timestamps |
Legacy Speed (non-Sonic-3)
| Parameter | Values | Description |
|---|---|---|
speed |
"slow", "normal", "fast" |
Speech rate for older models |
Emotion Controls (60+)
Available with Sonic-3 model:
Positive: happy, excited, enthusiastic, elated, euphoric, triumphant, amazed, content, peaceful, serene, calm, grateful, affectionate, proud, confident
Neutral: neutral, curious, contemplative, mysterious, determined
Negative: sad, angry, scared, frustrated, anxious, disappointed, hurt, guilty, bored, tired, rejected, nostalgic, resigned
Social: flirtatious, joking/comedic, sarcastic, ironic, sympathetic, apologetic, hesitant, insecure, skeptical, distant
Supported Languages (40+)
| Code | Language | Code | Language |
|---|---|---|---|
en |
English | ja |
Japanese |
es |
Spanish | ko |
Korean |
fr |
French | zh |
Chinese |
de |
German | hi |
Hindi |
pt |
Portuguese | ru |
Russian |
it |
Italian | nl |
Dutch |
sv |
Swedish | da |
Danish |
pl |
Polish | tr |
Turkish |
ar |
Arabic | cs |
Czech |
el |
Greek | fi |
Finnish |
hu |
Hungarian | no |
Norwegian |
ro |
Romanian | bg |
Bulgarian |
uk |
Ukrainian | vi |
Vietnamese |
id |
Indonesian | ms |
Malay |
th |
Thai | ta |
Tamil |
he |
Hebrew | bn |
Bengali |
te |
Telugu | gu |
Gujarati |
kn |
Kannada | ml |
Malayalam |
mr |
Marathi | pa |
Punjabi |
Error Handling
| Status | Meaning | Action |
|---|---|---|
| 400 | Bad request (invalid params, missing fields) | Check request body format |
| 401 | Invalid or missing API key | Verify X-API-Key header |
| 403 | Permission denied | Check API key permissions |
| 422 | Validation error | Check model_id, voice, output_format |
| 429 | Rate limited | Implement exponential backoff |
| 500 | Server error | Retry with backoff |
Cost
- Billing: Per character of text synthesized
- Free tier: Available for testing (limited chars/month)
- Pricing: https://cartesia.ai/pricing
Quick Test
# Test TTS generation (generates MP3 of a BDR intro)
curl -s -X POST "https://api.cartesia.ai/tts/bytes" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" \
-H "Content-Type: application/json" \
-d '{
"model_id": "sonic",
"transcript": "Hi, this is Kaji from Shakudo. We help companies build secure AI systems. Do you have thirty seconds?",
"voice": {"mode": "id", "id": "81db94f2-ea76-4e5a-94bf-c92be997270d"},
"output_format": {"container": "mp3", "bit_rate": 128000, "sample_rate": 44100}
}' -o test.mp3 && ls -la test.mp3
# Expected: MP3 file ~50-150KB with spoken audio
# If you get a file with audio, your API key is working!
# List English voices
curl -s "https://api.cartesia.ai/voices" \
-H "X-API-Key: $CARTESIA_API_KEY" \
-H "Cartesia-Version: 2024-06-10" | jq '[.[] | select(.language == "en") | {id, name}][:5]'