Text-to-Speech
POST /v1/audio/speech
Turn text into natural speech with one OpenAI-compatible endpoint. Send JSON, get audio bytes back — switch providers by changing modelonly. Nothing is written to disk: audio is streamed straight back to you.
Example Request
curl https://synthorai.io/v1/audio/speech \
-H "Authorization: Bearer $SYNTHORAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "tts-1",
"input": "Hello from Synthorai.",
"voice": "alloy"
}' \
--output speech.mp3 Python (OpenAI SDK)
from openai import OpenAI
client = OpenAI(
api_key="$SYNTHORAI_API_KEY",
base_url="https://synthorai.io/v1",
)
with client.audio.speech.with_streaming_response.create(
model="tts-1",
voice="alloy",
input="Hello from Synthorai.",
) as response:
response.stream_to_file("speech.mp3") Request Body
| Parameter | Type | Description |
|---|---|---|
model* | string | Model ID. One of tts-1, tts-1-hd, seed-tts-2.0. |
input* | string | The text to synthesise. Maximum 4096 characters. |
voice | string | Voice to speak in. Defaults to alloy. See Voices below. |
response_format | string | Audio container: mp3 (default), opus, wav or pcm. |
speed | number | Speaking rate, 0.25–4.0. Defaults to 1.0. |
Supported models
Which one should I use?
| You need | Recommended models |
|---|---|
| Cheapest, good enough for most product voice | google-tts-standard |
| Chinese-first content, or you want many voice options | qwen3-tts-instruct-flash seed-tts-2.0 |
| Everyday product voice, balancing quality against cost | tts-1 google-tts-neural2 |
| Best expressiveness — narration, companion devices, brand voice | tts-1-hd google-tts-chirp3-hd |
| Model | Price | Best for |
|---|---|---|
google-tts-standard | $4 / 1M chars | High-volume notifications and prompts where cost dominates |
qwen3-tts-instruct-flash | $11.50 / 1M chars | Chinese and multilingual content; upstream reports the billed character count |
tts-1 | $15 / 1M chars | General product voice, prompts, notifications |
google-tts-neural2 | $16 / 1M chars | Natural everyday voice across many languages |
tts-1-hd | $30 / 1M chars | Narration, marketing, anything users listen to for a while |
seed-tts-2.0 | $30 / 1M chars | Chinese and multilingual content; 180+ voices |
google-tts-chirp3-hd | $30 / 1M chars | Google's newest, most expressive voices |
Three models sit at $30 — they differ in voice character and language coverage, not price. Try them on your own copy before committing.
Switching providers costs you one line. Every model here speaks the same request and response shape. Providers differ wildly underneath (different auth, streaming formats, voice naming) — the gateway absorbs that so you only change model.
# Same request, different provider — only the model name changes.
-d '{"model": "tts-1", "input": "...", "voice": "alloy"}'
-d '{"model": "seed-tts-2.0", "input": "...", "voice": "alloy"}' Voices
OpenAI models accept the standard voices: alloy, echo, fable, onyx, nova, shimmer.
For seed-tts-2.0 the same six names work (they map to comparable voices), and you can also pass a native BytePlus voice ID directly for full control — for example zh_female_cancan_uranus_bigtts. The full list of 180+ native voices is in the BytePlus voice catalogue.
For qwen3-tts-instruct-flash the same six names work, or pass a native Qwen voice such as Cherry, Ethan, Nofish, Jada.
Google voices are tied to their price tier. Each Google model covers one tier, and the tier is part of the voice name. If you pass a native voice id such as en-US-Neural2-C you must use the matching model — google-tts-neural2 in that example. Cross-tier voices are rejected with a 502 rather than silently billed at the wrong rate.
Audio formats
Set response_format to pick the container. Default is mp3: mp3, opus, wav, pcm.
Not every provider supports every container; unsupported values fall back to MP3 rather than failing.
Billing
Charged per input character at the provider's official list price — no markup. One character = one Chinese character = one letter = one punctuation mark = one space. Failed requests are never charged.
The audio you get back is not metered separately; only the text you send in is.
Limits
- Maximum 4096 characters per request. Longer input is rejected before anything is charged — split it client-side and concatenate the audio.
- Speaking rate is controlled by
speed(0.25–4.0, default 1.0). Values outside the provider's range are clamped, not rejected.
Errors
| Response | Description |
|---|---|
400 | Input is empty, or longer than 4096 characters. |
401 | Missing or invalid API key. |
402 | Not enough quota for this request. |
502 | The model is not available on your account, or the upstream provider failed. Nothing is charged. |
503 | No channel currently serves this model. |