API Reference
API Reference / Endpoints / Speech

Streaming text to speech

/v1/speech/text-to-speech/stream

Receive speech audio progressively from complete input text.

POST/v1/speech/text-to-speech/stream
Auth: 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

FieldTypeRequiredDescription
textstringYesComplete non-blank text. Maximum 5000 UTF-16 code units; whitespace is preserved.
voice_idstringYesPublic Wubble voice_id from GET /v1/speech/voices. The voice must remain available and authorized.
model_idstringOptionalwubble_realtime_v1 (default and only supported model).
output_formatstringOptionalmp3_44100_128 (default), or pcm_24000: signed 16-bit little-endian mono at 24 kHz, without a WAV header.
language_codestringOptionalOptional 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_settingsobjectOptionalOptional 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?