TTS API
Synthesize speech from text using Revolab’s Nada voice models.
POST https://api.revolab.ai/v1/ttsRequest body (JSON)
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model | string | optional | "nada-1.0-flash" | Model to use for synthesis. Values: nada-1.0-flash-lite, nada-1.0-flash, nada-1.0-pro |
text | string | required | — | Text to synthesize. Maximum 500 characters. |
voice_id | string | required | — | Voice identifier. List the IDs your key accepts with GET /v1/voices. |
language | string | optional | "en" | BCP-47 language code (e.g., "en", "ms", "zh"). Defaults to English when omitted. |
speed | float | optional | null (normal speed) | Playback speed multiplier. Range: 0.5 (half speed) to 2.0 (double speed). |
output_format | string | optional | "wav" | Audio format of the output. Only WAV is supported in this release. |
stream | boolean | optional | false | true streams raw PCM audio as it is synthesized instead of a buffered WAV — see Streaming. |
Request examples
cURL
curl -X POST https://api.revolab.ai/v1/tts \
-H "Authorization: Bearer $REVOLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "nada-1.0-flash",
"text": "The quick brown fox jumped over the lazy dog.",
"voice_id": "<your-voice-id>",
"language": "en",
"speed": 1.0,
"output_format": "wav"
}'Response (200 OK)
The response body is the audio — a complete WAV file (Content-Type: audio/wav). Save it or pipe it straight to a player; there is no download
URL round-trip. Generation metrics ride as response headers:
| Header | Description |
|---|---|
X-Duration-S | Duration of the generated audio in seconds. |
X-Latency-Ms | Synthesis latency in milliseconds. |
X-Request-Id | Request id — quote it in support requests. |
curl -X POST https://api.revolab.ai/v1/tts \
-H "Authorization: Bearer $REVOLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "nada-1.0-flash", "voice_id": "<your-voice-id>", "text": "Hello!"}' \
-o hello.wavGenerations are still stored to your History (dashboard playback) — the upload happens in the background and never delays the response.
Streaming
Set "stream": true to receive audio while it is being synthesized,
instead of waiting for the full generation. Playback can start after the
first chunk — usually well under a second.
The streamed body is raw PCM: 24 kHz, mono, 16-bit little-endian
(pcm_s16le). Raw PCM is used because WAV cannot stream — its header is
length-prefixed. Two response headers describe the format so nothing is
out-of-band:
| Header | Value |
|---|---|
Content-Type | audio/pcm |
X-Sample-Rate | 24000 |
X-Audio-Format | pcm_s16le |
curl --no-buffer -X POST https://api.revolab.ai/v1/tts \
-H "Authorization: Bearer $REVOLAB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "nada-1.0-flash", "voice_id": "aisyah", "text": "Hello from Revolab!", "stream": true}' \
| ffplay -f s16le -ar 24000 -ch_layout mono -i - -autoexit -nodispNotes:
stream: trueonly supports the PCM stream — combining it with a non-defaultoutput_formatreturns400 validation_error.- Streamed generations are not stored; the stream is the delivery. Use the default buffered response when you want the generation kept in your History.
- Errors that occur before the first chunk (unknown voice, depleted balance, rate limits) return the normal JSON error envelope. Once audio starts flowing, the connection simply ends on failure — treat an unexpectedly short stream as an incomplete generation.
- Billing meters the audio actually delivered: disconnect early and you are charged only for what you received.
Using an OpenAI SDK instead? The OpenAI-compatible endpoint
offers the same stream via response_format: "pcm" (and an SSE framing via
stream_format: "sse").
Status codes
200 OK — Success
WAV audio bytes (audio/wav) with X-Duration-S / X-Latency-Ms headers.
400 Bad Request — Unknown model, text too long, invalid voice_id, or invalid output_format
{
"error": {
"code": "validation_error",
"message": "Unknown model 'nada-2.0'. Valid models: ['nada-1.0-flash', ...]",
"request_id": "req_01HXYZ..."
}
}401 Unauthorized — Missing, invalid, or revoked API key
{
"error": {
"code": "unauthorized",
"message": "Invalid API key format. Keys must start with 'rvl_live_'.",
"request_id": "req_01HXYZ..."
}
}422 Unprocessable Entity — Request body fails JSON schema validation (e.g., missing required field)
{
"detail": [
{
"loc": ["body", "text"],
"msg": "field required",
"type": "value_error.missing"
}
]
}402 Payment Required — The organization’s balance is depleted
{
"error": {
"code": "insufficient_balance",
"message": "Insufficient balance to complete this request.",
"request_id": "req_01HXYZ..."
}
}429 Too Many Requests — Rate limit exceeded
Also quota_exceeded (monthly cap) and concurrency_limit_exceeded (too many
in-flight requests); honor Retry-After.
{
"error": {
"code": "rate_limited",
"message": "Rate limit exceeded.",
"request_id": "req_01HXYZ..."
}
}502 Bad Gateway — TTS model endpoint returned an error or malformed audio
{
"error": {
"code": "endpoint_unavailable",
"message": "The upstream TTS service returned an unexpected response.",
"request_id": "req_01HXYZ..."
}
}503 Service Unavailable — TTS service is under maintenance or endpoint config is missing
{
"error": {
"code": "service_unavailable",
"message": "TTS service is temporarily unavailable.",
"request_id": "req_01HXYZ..."
}
}Related
- Voices API — list the
voice_idvalues your key accepts - Models — compare Nada models
- Error catalog — full list of error codes
- Authentication — how to send your API key