API Reference / Endpoints / Speech
Streaming text to speech
/v1/speech/text-to-speech/streamReceive speech audio progressively from complete input text.
POST
/v1/speech/text-to-speech/streamAuth: Wubble API key only (not a dashboard JWT)Billing: Consumes 1 API callBehavior: Streaming audioScopes: audio:generate
POSTStreaming audiojsonaudio:generate
When to use it
Use this when playback should begin before synthesis finishes. Send complete text in one POST; the response is audio bytes, not SSE, WebSocket messages, a JSON job, or a downloadable URL.
Behavior on success
Returns 200 with progressive binary audio. Use X-Request-ID to check final status, especially after interruption. No recording URL is returned.
Integration shape
Authorization model
audio:generate
Request format
json
Polling pattern
No polling required on the normal success path.
Request
| Field | Type | Required | Description |
|---|---|---|---|
text | string | Yes | Complete non-blank text. Maximum 5000 UTF-16 code units; whitespace is preserved. |
voice_id | string | Yes | Public Wubble voice_id from GET /v1/speech/voices. The voice must remain available and authorized. |
model_id | string | Optional | wubble_realtime_v1 (default and only supported model). |
output_format | string | Optional | mp3_44100_128 (default), or pcm_24000: signed 16-bit little-endian mono at 24 kHz, without a WAV header. |
language_code | string | Optional | Optional supported language code: en, ja, zh, de, hi, fr, ko, pt, it, es, id, nl, tr, fil, pl, sv, bg, ro, ar, cs, el, fi, hr, ms, sk, da, ta, uk, ru, hu, no, vi. |
voice_settings | object | Optional | Optional stability, similarity_boost and style (0–1), use_speaker_boost (boolean), and speed (0.7–1.2). Unknown fields are rejected. |
Example request
POST /v1/speech/text-to-speech/stream
// Node.js: keep API keys on your server. No automatic POST retries.
import { createWriteStream } from 'node:fs';
import { Readable } from 'node:stream';
import { pipeline } from 'node:stream/promises';
const response = await fetch('https://prod-backup-backend.wubble.ai/v1/speech/text-to-speech/stream', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.WUBBLE_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': crypto.randomUUID(),
},
body: JSON.stringify({
text: 'Hello from Wubble.',
voice_id: 'REPLACE_WITH_PUBLIC_WUBBLE_VOICE_ID',
model_id: 'wubble_realtime_v1',
output_format: 'mp3_44100_128',
}),
signal: AbortSignal.timeout(110000),
});
if (!response.ok) throw new Error(`Wubble HTTP ${response.status}`);
if (!response.body || !response.headers.get('content-type')?.startsWith('audio/mpeg')) {
throw new Error('Expected MP3 audio');
}
console.log('Wubble request:', response.headers.get('x-request-id'));
// Backpressure-aware progressive saving. Use a streaming audio player for live playback.
await pipeline(Readable.fromWeb(response.body), createWriteStream('speech.mp3'));
// On interruption, the file may be partial. Check GET /v1/requests/:requestId.Example response
Response shapehttp
HTTP/1.1 200 OK
Content-Type: audio/mpeg
Cache-Control: no-store
X-Request-ID: <wubble-request-uuid>
X-Wubble-Audio-Format: mp3_44100_128
<progressively delivered binary audio bytes>Implementation notes
Idempotency-Key is required: 1–128 characters using letters, digits, periods, underscores, colons or hyphens. Generate a fresh key for a new intentional request. Repeating a key returns 409; streams cannot be replayed.
A successful stream consumes one API call. Allowance is reserved at admission; failures before billable audio are released. Cancellation or failure after audio starts may still be billed. GET /v1/requests/:requestId provides the final status.
The response contains audio directly. There is no saved recording or stream URL to expire. Your client must retain audio if needed; do not use response.json() on a successful response.
Before audio starts, failures return Wubble JSON with success=false, data=null, request_id, and error.code/message. Handle 400/413 input errors, 401/403 authentication or scope errors, 402 allowance, 409 replay conflicts, 429 rate/account/fleet capacity, and 502/503/504 service failures.
After audio headers have been sent, a failure terminates the connection; no JSON error can be appended safely. Check X-Request-ID against GET /v1/requests/:requestId. HTTP 200 alone does not prove complete audio.
Account active-generation limits are shared with other generation endpoints. Fleet streaming capacity is an additional limit, not a guaranteed per-account allocation.
Use the dedicated streaming playground panel for browser playback and first-audio timing. It uses PCM; MP3 remains the API default. Audio-arrival timing and audible playback timing are different.
Production guidance
Pair this route with idempotency on POST requests and either request polling or webhooks whenever the response is asynchronous.
Was this page helpful?