Skip to main content

Connection

/ws/tts and /ws are equivalent (same handler, two paths). The handshake also accepts an X-API-Key: sk_... header — preferred outside the browser, since it keeps the key out of the URL (see Authentication).

Request

Send a JSON message after connecting. You can send multiple requests over the same connection — each is a fresh synthesis job.

Response

  • Binary messages: Raw Int16 PCM audio chunks (44.1 kHz, mono). Large chunks are split into ≤512KB WebSocket frames.
  • Text message "EOS": Synthesis complete for this request — the connection stays open for further requests.
  • JSON visemes: A bare JSON array of { v, c, t, id } objects (not wrapped in a {"type":...} envelope) — sent only if visemes: true and only when the model actually produced viseme data for that chunk.
  • JSON timing (optional, streaming mode only): { "type": "timing", "timing": { ... RTF, IsFirst, ... }, "ttfb_ms"?: number } — internal performance telemetry sent alongside some chunks; ttfb_ms is only present on the first chunk. Treat this as informational, not part of the audio contract.
  • JSON error: { "type": "error", "data": { "code": "...", "message": "...", "detail": "...", "retryable": true|false } } — same structured shape as every other Lokutor error; see the Error Catalog. This is not a bare {"type":"error","message":"..."} — the payload is under data, and it’s the full structured object.

Best practices

  • Keep the WebSocket open for multiple requests to avoid handshake latency
  • The stream runs at 6 denoising steps, tuned for live conversation; for offline audio at up to 8, use REST POST /tts/synthesize
  • Validate inputs against GET /config before sending
  • Always pass voice and language explicitly — neither has a server-side default on this endpoint

Languages

All nine supported languages are available.