---
title: "WebSocket Input Streaming (LLM token stream to speech)"
url: "https://dev.silma.ai/apis/silma-tts-api-2/versions/d7a27b7e-ba8b-495a-a2a3-3cdf9c2b4be3/paths/ws-input_stream/get"
---

> Full API specification: https://dev.silma.ai/apis/silma-tts-api-2/versions/d7a27b7e-ba8b-495a-a2a3-3cdf9c2b4be3.md

# WebSocket Input Streaming (LLM token stream to speech)

`GET` `/ws/input_stream`

For voice agents: pipe your LLM's token stream in and get one continuous, real-time-paced audio stream back. **Handshake:** Upgrade request to `wss://api.silma.ai/tts/v2/ws/input_stream`. **Client messages (JSON):** 1. `{"type":"init", ...}` with the `TTSRequest` fields except `text` (`model_id`, `voice_id`, `speech_rate`, `creativity`, `seed`, ...), plus optional `idle_flush_ms` (0-10000, default 400): when the LLM is quiet this long and no speech is pending, the words buffered so far are spoken without waiting for the end of the sentence (0 disables). 2. `{"type":"text","text":"<chunk>"}`: send each chunk of text your LLM streams (usually one token, e.g. `" can"`) as soon as you receive it. Chunks of any size are accepted (a character, a token, a sentence, or the whole answer); they are joined exactly as sent, so forward them unchanged, keeping their leading/trailing spaces. 3. `{"type":"flush"}` to speak whatever is buffered now. 4. `{"type":"end"}` when the LLM is done, or `{"type":"cancel"}` to stop at once (barge-in). After either, the socket accepts a new `init`. **Server messages:** - `started` (`sample_rate`, `model_id`, `max_characters`). - `streaming`: `audio` (base64 float32 mono PCM) and `text` (the segment being spoken; `""` for silence). Text is spoken one segment at a time, released at sentence ends (or a clause for the first segment, or a length cap). From the first speech chunk on, audio is sent at about 1x real time and gaps are filled with silence, until `end`/`cancel`. Gap-filling silence messages also carry `silence`: `"llm"` (waiting for more text) or `"tts"` (text is being synthesized). - `warning` (`warning`): non-fatal, e.g. the character limit was reached. - `completed` / `cancelled` with `billed_characters` and `stats` (`ttfa_ms`, `segments`, `underruns`, `tts_wait_sec`, `llm_wait_sec`). Billing is once per session, for the characters actually spoken. On `cancel`, stop local playback yourself: audio already sent is not recalled. - `failed` (`error`), followed by a close (1008 invalid input, 1011 server error).

## Responses

- `101` - Switching Protocols to WebSocket.

## OpenAPI definition

```yaml
openapi: 3.1.0
info:
  title: SILMA TTS v2 API
  version: 2.3.1
servers:
  - url: https://api.silma.ai/tts/v2
paths:
  /ws/input_stream:
    get:
      summary: WebSocket Input Streaming (LLM token stream to speech)
      description: >
        For voice agents: pipe your LLM's token stream in and get one
        continuous, real-time-paced audio stream back.

        **Handshake:** Upgrade request to
        `wss://api.silma.ai/tts/v2/ws/input_stream`.

        **Client messages (JSON):**

        1. `{"type":"init", ...}` with the `TTSRequest` fields except `text`
        (`model_id`, `voice_id`, `speech_rate`, `creativity`, `seed`, ...),
           plus optional `idle_flush_ms` (0-10000, default 400): when the LLM is quiet this long and no speech is pending,
           the words buffered so far are spoken without waiting for the end of the sentence (0 disables).
        2. `{"type":"text","text":"<chunk>"}`: send each chunk of text your LLM
        streams (usually one token, e.g. `" can"`) as soon as you receive it.
           Chunks of any size are accepted (a character, a token, a sentence, or the whole answer); they are joined exactly as sent,
           so forward them unchanged, keeping their leading/trailing spaces.
        3. `{"type":"flush"}` to speak whatever is buffered now.

        4. `{"type":"end"}` when the LLM is done, or `{"type":"cancel"}` to stop
        at once (barge-in). After either, the socket accepts a new `init`.

        **Server messages:**

        - `started` (`sample_rate`, `model_id`, `max_characters`).

        - `streaming`: `audio` (base64 float32 mono PCM) and `text` (the segment
        being spoken; `""` for silence).
          Text is spoken one segment at a time, released at sentence ends (or a clause for the first segment, or a length cap).
          From the first speech chunk on, audio is sent at about 1x real time and gaps are filled with silence, until `end`/`cancel`.
          Gap-filling silence messages also carry `silence`: `"llm"` (waiting for more text) or `"tts"` (text is being synthesized).
        - `warning` (`warning`): non-fatal, e.g. the character limit was
        reached.

        - `completed` / `cancelled` with `billed_characters` and `stats`
        (`ttfa_ms`, `segments`, `underruns`, `tts_wait_sec`, `llm_wait_sec`).
          Billing is once per session, for the characters actually spoken. On `cancel`, stop local playback yourself: audio already sent is not recalled.
        - `failed` (`error`), followed by a close (1008 invalid input, 1011
        server error).
      responses:
        "101":
          description: Switching Protocols to WebSocket.
security:
  - ApiKeyAuth: []
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: apiKey
```
