Create Speech
Generate audio from text using the Nineninesix TTS API.
POST /tts/bytes
Generates audio from the input transcript. The response body is the raw audio in the requested format, streamed as it's generated.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
model_id | string | Yes | The TTS model. Currently gepard-1.0. |
transcript | string | Yes | The text to synthesize. |
voice | object | Yes | Voice specifier: { "mode": "id", "id": "<voice-id>" }. |
output_format | object | Yes | Output format (see below). |
language | string | No | Language code (e.g. en). |
Output Format
The model is natively 22050 Hz. Set sample_rate to 22050 to skip resampling; any other rate is resampled server-side. encoding may be pcm_s16le or pcm_f32le.
// WAV (PCM)
{ "container": "wav", "encoding": "pcm_s16le", "sample_rate": 22050 }
// Raw PCM (lowest latency for streaming pipelines)
{ "container": "raw", "encoding": "pcm_s16le", "sample_rate": 22050 }MP3 is not yet supported — the API currently emits wav and raw PCM only. MP3 (container: "mp3") is planned; for now request wav and transcode client-side if you need MP3.
Models
| Model | Description |
|---|---|
gepard-1.0 | Dialogue-native model, tuned for conversational speech and low-latency streaming. |
Billing
1 credit = 1 character of transcript (Unicode code points). The charge is taken before generation and refunded automatically on failure.
Examples
curl -N https://api.nineninesix.ai/tts/bytes \
-H "Authorization: Bearer sk_996_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model_id": "gepard-1.0",
"transcript": "Today is a wonderful day to build something people love!",
"voice": { "mode": "id", "id": "<voice-id>" },
"output_format": { "container": "wav", "encoding": "pcm_s16le", "sample_rate": 22050 }
}' --output speech.wavfrom cartesia import Cartesia
client = Cartesia(api_key="sk_996_your_api_key", base_url="https://api.nineninesix.ai")
audio = client.tts.bytes(
model_id="gepard-1.0",
transcript="Today is a wonderful day to build something people love!",
voice={"mode": "id", "id": "<voice-id>"},
output_format={"container": "wav", "encoding": "pcm_s16le", "sample_rate": 22050},
)
with open("speech.wav", "wb") as f:
f.write(audio)import { Cartesia } from "@cartesia/cartesia-js";
const client = new Cartesia({ apiKey: "sk_996_your_api_key", baseURL: "https://api.nineninesix.ai" });
const res = await client.tts.generate({
model_id: "gepard-1.0",
transcript: "Today is a wonderful day to build something people love!",
voice: { mode: "id", id: "<voice-id>" },
output_format: { container: "wav", encoding: "pcm_s16le", sample_rate: 22050 },
});
const buffer = Buffer.from(await res.arrayBuffer());
fs.writeFileSync("speech.wav", buffer);POST /tts/sse
Streams audio over Server-Sent Events for low time-to-first-audio without opening a WebSocket. The request body is identical to /tts/bytes, except the container must be raw (SSE can't wrap a WAV/RIFF header):
{ "container": "raw", "encoding": "pcm_s16le", "sample_rate": 22050 }Each event's data is a JSON object. chunk events carry a base64-encoded slice of raw PCM; a final done event closes the stream:
data: {"type":"chunk","data":"<base64 pcm>","context_id":"..."}
data: {"type":"chunk","data":"<base64 pcm>","context_id":"..."}
data: {"type":"done","context_id":"..."}Billing is identical to /tts/bytes — one pre-charge on the full transcript, confirmed when the stream completes.
import { Cartesia } from "@cartesia/cartesia-js";
const client = new Cartesia({ apiKey: "sk_996_your_api_key", baseURL: "https://api.nineninesix.ai" });
const stream = await client.tts.generateSSE({
model_id: "gepard-1.0",
transcript: "Streaming speech, chunk by chunk.",
voice: { mode: "id", id: "<voice-id>" },
output_format: { container: "raw", encoding: "pcm_s16le", sample_rate: 22050 },
});
for await (const message of stream) {
if (message.type === "chunk") {
const pcm = Buffer.from(message.data, "base64"); // feed into your audio sink
}
}import base64
from cartesia import Cartesia
client = Cartesia(api_key="sk_996_your_api_key", base_url="https://api.nineninesix.ai")
for message in client.tts.sse(
model_id="gepard-1.0",
transcript="Streaming speech, chunk by chunk.",
voice={"mode": "id", "id": "<voice-id>"},
output_format={"container": "raw", "encoding": "pcm_s16le", "sample_rate": 22050},
):
if message.type == "chunk":
pcm = base64.b64decode(message.data) # feed into your audio sinkWebSocket Streaming
GET /tts/websocket
For real-time, low-latency generation, open a WebSocket connection. Each transcript frame is billed and synthesized independently; audio frames stream back per context_id.
Because browsers and many WebSocket clients can't set headers, pass your key as a query parameter:
wss://api.nineninesix.ai/tts/websocket?api_key=sk_996_your_api_keySend one JSON frame per utterance; group related frames under a shared context_id:
{
"model_id": "gepard-1.0",
"transcript": "Hello there.",
"voice": { "mode": "id", "id": "<voice-id>" },
"output_format": { "container": "raw", "encoding": "pcm_s16le", "sample_rate": 22050 },
"context_id": "conversation-1"
}The server streams back chunk frames (base64 raw PCM) for that context_id, then a done frame; an error frame is sent instead if synthesis fails. Each transcript frame is billed and settled independently — confirmed on done, refunded on error. Control frames without a transcript are not billed.
The Cartesia SDK's client.tts.websocket() helper manages the connection and framing for you.
Error Responses
| Status | Error | Description |
|---|---|---|
| 400 | missing_transcript / invalid_json | Malformed request body |
| 401 | unauthorized | Missing or invalid API key |
| 402 | payment_required | Insufficient credits |
| 429 | rate_limited / concurrent_limit | Per-project rate or concurrency limit reached |
| 502 | upstream_unavailable | Synthesis backend error |
Error response format:
{ "error": "payment_required", "message": "insufficient credits" }