# Cartesia Tts

> Cartesia Text-to-Speech (TTS) - Sonic-3 model with ~90ms first-byte latency, 40+ languages, 60+ emotion controls, and WebSocket streaming. Use for real-time voice synthesis, conversational AI, voice AI pipelines (Pipecat), and telephony applications.

- Skill: `shakudo-io/cartesia-tts` (Agent Skill)
- Install (CLI): `npx skillmds@latest add shakudo-io/cartesia-tts`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shakudo-io/cartesia-tts/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- License: MIT
- Author: Shakudo-io (https://skillmd.com/u/shakudo-io)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/shakudo-io/cartesia-tts

---


# 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:

```bash
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

```bash
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

```bash
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)

```bash
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

```bash
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

```bash
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

```json
{
  "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

```python
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:**
```json
{
  "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:**
```json
{"context_id": "unique-context-id", "cancel": true}
```

**Receive — Audio Chunk:**
```json
{"type": "chunk", "data": "base64_pcm_audio", "done": false, "status_code": 206, "step_time": 45, "context_id": "..."}
```

**Receive — Timestamps:**
```json
{"type": "timestamps", "word_timestamps": {"words": ["Hello", "world"], "start": [0.0, 0.5], "end": [0.4, 0.9]}, "context_id": "..."}
```

**Receive — Done:**
```json
{"type": "done", "done": true, "status_code": 206, "context_id": "..."}
```

## Pipecat Integration

For voice AI pipelines using Pipecat with Cartesia TTS:

```python
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)

```python
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

```python
# 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

```bash
# 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]'
```

