> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gnani.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Text-to-Speech (Streaming)

> Stream audio in chunks as it's generated via Server-Sent Events.

## Overview

Receive audio in chunks as it's generated, allowing playback to start immediately. Reduces latency compared to [TTS REST](/api/TTS/tts-inference). For the lowest latency, see [TTS Realtime](/api/TTS/tts-websocket).

<Note>
  Passing numbers, IDs, dates, or currency as raw strings causes mispronunciations. See the [Input Formatting Guide](/api/TTS/tts-input-formating) for correct formatting of phone numbers, account numbers, PINs, Aadhaar, vehicle registration numbers, GSTIN, currency, and more.
</Note>

***

## Models

| Model       | `model` value | Voices              | Extra parameters    |
| :---------- | :------------ | :------------------ | :------------------ |
| Timbre v2.0 | `timbre-v2.0` | English, Hindi      | —                   |
| Timbre v2.5 | `timbre-v2.5` | 10 Indian languages | `language`, `speed` |

<Tip>
  Use **Timbre v2.5** for multilingual support, and a much wider voice catalog.
</Tip>

***

## Endpoint

```text theme={null}
POST https://api.vachana.ai/api/v1/tts/sse
```

***

## Authentication

| Header         | Required | Description        |
| :------------- | :------- | :----------------- |
| `X-API-Key-ID` | ✅        | Your Gnani API key |

***

## Request Parameters

<Tabs>
  <Tab title="Timbre v2.5">
    ```json theme={null}
    {
      "text": "नमस्ते, आप कैसे हैं?",
      "voice": "Nalini",
      "model": "timbre-v2.5",
      "language": "hi-IN",
      "speed": 1.0,
      "audio_config": {
        "sample_rate": 48000,
        "num_channels": 1,
        "sample_width": 2,
        "encoding": "linear_pcm",
        "container": "wav"
      }
    }
    ```

    <ParamField body="text" type="string" required>
      The text to synthesize into speech. Pass numbers, dates, and currency as spoken words to avoid mispronunciations — see [Input Formatting Guide](/api/TTS/tts-input-formating).
    </ParamField>

    <ParamField body="model" type="string" required>
      Set to `timbre-v2.5`.
    </ParamField>

    <ParamField body="voice" type="string" required>
      Voice name from the Timbre v2.5 catalog. See the [Voice Catalog](/api/TTS/available-voices). Example: `Nalini`, `Kaveri`, `Deepak`.
    </ParamField>

    <ParamField body="language" type="string" required>
      Language of the input text. Controls text normalization and routing.

      | Value   | Language                                                |
      | :------ | :------------------------------------------------------ |
      | `auto`  | Auto-detect from script (recommended for mixed content) |
      | `hi-IN` | Hindi                                                   |
      | `en-IN` | English                                                 |
      | `ta-IN` | Tamil                                                   |
      | `te-IN` | Telugu                                                  |
      | `kn-IN` | Kannada                                                 |
      | `ml-IN` | Malayalam                                               |
      | `mr-IN` | Marathi                                                 |
      | `pa-IN` | Punjabi                                                 |
      | `bn-IN` | Bengali                                                 |
      | `gu-IN` | Gujarati                                                |
    </ParamField>

    <ParamField body="speed" type="number | string" default="1.0">
      Playback speed multiplier. Numeric range: `0.85` (slowest) to `1.15` (fastest). String shortcuts: `"slow"` = 0.85, `"medium"` = 1.0, `"fast"` = 1.15.
    </ParamField>

    <ParamField body="audio_config" type="object">
      Controls the format of the returned audio.

      <Expandable title="audio_config fields">
        <ParamField body="audio_config.sample_rate" type="integer" default="48000">
          Sample rate in Hz. Supported: `8000`, `16000`, `22050`, `24000`, `44100`, `48000`.
        </ParamField>

        <ParamField body="audio_config.num_channels" type="integer" default="1">
          Number of audio channels. `1` for mono.
        </ParamField>

        <ParamField body="audio_config.sample_width" type="integer" default="2">
          Sample width in bytes. `2` for 16-bit audio.
        </ParamField>

        <ParamField body="audio_config.encoding" type="string" default="linear_pcm">
          Audio encoding format. Options: `linear_pcm`, `pcm_s16le`, `pcm_mulaw`, `pcm_alaw`, `oggopus`. For telephony, prefer `container=mulaw` or `container=alaw` over this field — both produce the same output. Use `oggopus` (or `container=ogg`) for a playable OGG Opus file. Not required when `container` is `mp3`.
        </ParamField>

        <ParamField body="audio_config.container" type="string" default="wav">
          Output container format. Options: `wav`, `raw`, `mp3`, `ogg`, `mulaw`, `alaw`. Use `ogg` for OGG Opus. Use `mulaw` or `alaw` for G.711 telephony (forces 8000 Hz).
        </ParamField>

        <ParamField body="audio_config.bitrate" type="string" default="128k">
          MP3 bitrate. Only used when `container` is `mp3`. Supported: `32k`, `64k`, `96k`, `128k`, `192k`.
        </ParamField>
      </Expandable>
    </ParamField>
  </Tab>

  <Tab title="Timbre v2.0">
    ```json theme={null}
    {
      "text": "नमस्ते, आप कैसे हैं?",
      "voice": "Pranav",
      "model": "timbre-v2.0",
      "language": "IND-IN",
      "audio_config": {
        "sample_rate": 48000,
        "num_channels": 1,
        "sample_width": 2,
        "encoding": "linear_pcm",
        "container": "wav"
      }
    }
    ```

    <ParamField body="text" type="string" required>
      The text to synthesize into speech. Pass numbers, dates, and currency as spoken words to avoid mispronunciations — see [Input Formatting Guide](/api/TTS/tts-input-formating).
    </ParamField>

    <ParamField body="model" type="string" required>
      Set to `timbre-v2.0`.
    </ParamField>

    <ParamField body="voice" type="string" required>
      Voice name. One of: `Pranav`, `Kaveri`, `Shubhra`, `Deepak`.
    </ParamField>

    <ParamField body="language" type="string" default="IND-IN">
      Language of the input text. Use `IND-IN` for this model.
    </ParamField>

    <ParamField body="audio_config" type="object">
      Controls the format of the returned audio.

      <Expandable title="audio_config fields">
        <ParamField body="audio_config.sample_rate" type="integer" default="48000">
          Sample rate in Hz. Supported: `8000`, `16000`, `22050`, `24000`, `44100`, `48000`.
        </ParamField>

        <ParamField body="audio_config.num_channels" type="integer" default="1">
          Number of audio channels. `1` for mono, `2` for stereo.
        </ParamField>

        <ParamField body="audio_config.sample_width" type="integer" default="2">
          Sample width in bytes. `2` for 16-bit audio.
        </ParamField>

        <ParamField body="audio_config.encoding" type="string" default="linear_pcm">
          Audio encoding format. Options: `linear_pcm`, `pcm_s16le`, `pcm_mulaw`, `pcm_alaw`, `oggopus`. For telephony, prefer `container=mulaw` or `container=alaw` over this field — both produce the same output. Use `oggopus` (or `container=ogg`) for a playable OGG Opus file. Not required when `container` is `mp3`.
        </ParamField>

        <ParamField body="audio_config.container" type="string" default="wav">
          Output container format. Options: `wav`, `raw`, `mp3`, `ogg`, `mulaw`, `alaw`. Use `ogg` for OGG Opus. Use `mulaw` or `alaw` for G.711 telephony (forces 8000 Hz).
        </ParamField>

        <ParamField body="audio_config.bitrate" type="string" default="128k">
          MP3 bitrate. Only used when `container` is `mp3`. Supported: `32k`, `64k`, `96k`, `128k`, `192k`.
        </ParamField>
      </Expandable>
    </ParamField>
  </Tab>
</Tabs>

***

## Audio Format Reference

| `container` | `encoding`   | Output                 | `sample_rate`      | `bitrate`    | Content-Type               |
| ----------- | ------------ | ---------------------- | ------------------ | ------------ | -------------------------- |
| `wav`       | `linear_pcm` | WAV file (with header) | 8000–48000 Hz      | —            | `audio/wav`                |
| `raw`       | `linear_pcm` | Raw 16-bit PCM         | 8000–48000 Hz      | —            | `application/octet-stream` |
| `mp3`       | —            | MP3 file               | 8000–48000 Hz      | `32k`–`192k` | `audio/mpeg`               |
| `ogg`       | —            | OGG Opus file          | 8000–48000 Hz      | —            | `audio/ogg`                |
| `mulaw`     | —            | Raw G.711 µ-law        | **forced 8000 Hz** | —            | `audio/basic`              |
| `alaw`      | —            | Raw G.711 A-law        | **forced 8000 Hz** | —            | `audio/alaw`               |

**Encoding aliases** — produce identical output to the `container` rows above:

| `container`    | `encoding`  | Equivalent to     |
| -------------- | ----------- | ----------------- |
| `raw`          | `pcm_mulaw` | `container=mulaw` |
| `raw`          | `pcm_alaw`  | `container=alaw`  |
| `raw` or `ogg` | `oggopus`   | `container=ogg`   |

`bitrate` only applies when `container=mp3`. `container=mulaw`/`alaw` override `sample_rate` to 8000 Hz.

<Note>
  When `container=ogg` or `encoding=oggopus` is requested, all audio chunks are encoded into a single OGG Opus file delivered as one chunk — streaming delivery is not possible for OGG.
</Note>

***

## Response

The server sends audio as a stream of Server-Sent Events. Each `chunk` event carries a base64-encoded audio fragment. A final `complete` event signals that synthesis is finished.

```text theme={null}
event: start
data: {"status": "streaming_started", "text": "नमस्ते, आप कैसे हैं?"}

event: chunk
data: {"chunk_index": 1, "audio": "<base64-encoded audio>", "is_final": false}

event: chunk
data: {"chunk_index": 2, "audio": "<base64-encoded audio>", "is_final": false}

event: complete
data: {"chunk_index": 3, "audio": "", "is_final": true}
```

| Event      | Description                                                                       |
| :--------- | :-------------------------------------------------------------------------------- |
| `start`    | Synthesis has begun.                                                              |
| `chunk`    | An audio fragment. Decode `audio` from base64 and append to your buffer in order. |
| `complete` | All audio has been sent. `is_final: true`, `audio` is empty.                      |
| `error`    | Synthesis failed. Contains `error`, `message`, and `status_code`.                 |

***

## Code Example

<Tabs>
  <Tab title="Timbre V2.5">
    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.vachana.ai/api/v1/tts/sse \
        -H "Content-Type: application/json" \
        -H "X-API-Key-ID: <your-api-key>" \
        -d '{
          "text": "नमस्ते, आप कैसे हैं?",
          "voice": "Nalini",
          "model": "timbre-v2.5",
          "language": "hi-IN",
          "speed": 1.0,
          "audio_config": {
            "sample_rate": 48000,
            "encoding": "linear_pcm",
            "container": "wav"
          }
        }'
      ```

      ```javascript JavaScript theme={null}
      const response = await fetch("https://api.vachana.ai/api/v1/tts/sse", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-Key-ID": "<your-api-key>",
        },
        body: JSON.stringify({
          text: "नमस्ते, आप कैसे हैं?",
          voice: "Nalini",
          model: "timbre-v2.5",
          language: "hi-IN",
          speed: 1.0,
          audio_config: {
            sample_rate: 48000,
            encoding: "linear_pcm",
            container: "wav",
          },
        }),
      });

      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        console.log(decoder.decode(value));
      }
      ```

      ```python Python theme={null}
      import requests, base64

      response = requests.post(
          "https://api.vachana.ai/api/v1/tts/sse",
          headers={
              "Content-Type": "application/json",
              "X-API-Key-ID": "<your-api-key>",
          },
          json={
              "text": "नमस्ते, आप कैसे हैं?",
              "voice": "Nalini",
              "model": "timbre-v2.5",
              "language": "hi-IN",
              "speed": 1.0,
              "audio_config": {
                  "sample_rate": 48000,
                  "encoding": "linear_pcm",
                  "container": "wav",
              },
          },
          stream=True,
      )

      for line in response.iter_lines():
          if line:
              print(line.decode("utf-8"))
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Timbre V2.0">
    <CodeGroup>
      ```bash cURL theme={null}
      curl -X POST https://api.vachana.ai/api/v1/tts/sse \
        -H "Content-Type: application/json" \
        -H "X-API-Key-ID: <your-api-key>" \
        -d '{
          "text": "नमस्ते, आप कैसे हैं?",
          "voice": "Pranav",
          "model": "timbre-v2.0",
          "language": "IND-IN",
          "audio_config": {
            "sample_rate": 48000,
            "encoding": "linear_pcm",
            "container": "wav"
          }
        }'
      ```

      ```javascript JavaScript theme={null}
      const response = await fetch("https://api.vachana.ai/api/v1/tts/sse", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-Key-ID": "<your-api-key>",
        },
        body: JSON.stringify({
          text: "नमस्ते, आप कैसे हैं?",
          voice: "Pranav",
          model: "timbre-v2.0",
          language: "IND-IN",
          audio_config: {
            sample_rate: 48000,
            encoding: "linear_pcm",
            container: "wav",
          },
        }),
      });

      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        console.log(decoder.decode(value));
      }
      ```

      ```python Python theme={null}
      import requests

      response = requests.post(
          "https://api.vachana.ai/api/v1/tts/sse",
          headers={
              "Content-Type": "application/json",
              "X-API-Key-ID": "<your-api-key>",
          },
          json={
              "text": "नमस्ते, आप कैसे हैं?",
              "voice": "Pranav",
              "model": "timbre-v2.0",
              "language": "IND-IN",
              "audio_config": {
                  "sample_rate": 48000,
                  "encoding": "linear_pcm",
                  "container": "wav",
              },
          },
          stream=True,
      )

      for line in response.iter_lines():
          if line:
              print(line.decode("utf-8"))
      ```
    </CodeGroup>
  </Tab>
</Tabs>

***

## Available Voices

<Tabs>
  <Tab title="Timbre  v2.5">
    44 high-quality voices across 9 Indian languages and English. See the full [Voice Catalog](/api/TTS/available-voices) for all voice names, languages, and descriptions.

    Popular examples: `Nalini` (Hindi, Female), `Kaveri` (English, Female), `Deepak` (Hindi, Male), `Girish` (English, Male).
  </Tab>

  <Tab title="Timbre  v2.0">
    4 voices for Hindi and English. See the full [Voice Catalog](/api/TTS/available-voices) for all voice names, languages, and descriptions. Also supports Voice cloning Refer to [Voice CLoning](/api/VC/voice-clone-embeddings)
  </Tab>
</Tabs>

***

## Python SDK

The SDK's streaming client handles SSE parsing and chunk reassembly for you — you just iterate and write.

### Installation

```bash theme={null}
pip install gnani-vachana
```

Requires **Python 3.10+**.

### Authentication

<CodeGroup>
  ```python Constructor argument theme={null}
  from gnani.tts import GnaniTTSStreamClient

  client = GnaniTTSStreamClient(api_key="your-api-key")
  ```

  ```bash Environment variable theme={null}
  export GNANI_API_KEY="your-api-key"
  ```

  ```python Environment variable (usage) theme={null}
  from gnani.tts import GnaniTTSStreamClient

  client = GnaniTTSStreamClient()
  ```
</CodeGroup>

### Stream Audio to a File

`synthesize_stream` yields audio chunks as they arrive. Playback or writing can begin before the full response is complete.

```python theme={null}
from gnani.tts import GnaniTTSStreamClient

client = GnaniTTSStreamClient(api_key="your-api-key")

with open("output.wav", "wb") as f:
    for chunk in client.synthesize_stream(
        "नमस्ते, आप कैसे हैं?",
        voice="Nalini",
        model="timbre-v2.5",
        language="hi-IN",
    ):
        f.write(chunk)
```

### With Custom Audio Config

```python theme={null}
from gnani.tts import GnaniTTSStreamClient, AudioConfig

client = GnaniTTSStreamClient(api_key="your-api-key")

with open("output.wav", "wb") as f:
    for chunk in client.synthesize_stream(
        "नमस्ते, आप कैसे हैं?",
        voice="Nalini",
        model="timbre-v2.5",
        language="hi-IN",
        audio_config=AudioConfig(
            sample_rate=48000,
            encoding="linear_pcm",
            container="wav",
        ),
    ):
        f.write(chunk)
```


## OpenAPI

````yaml POST /api/v1/tts/sse
openapi: 3.1.0
info:
  title: TTS Server
  description: Text-to-Speech API with WebSocket, SSE and gRPC streaming support
  version: 1.0.0
servers:
  - url: https://api.vachana.ai
    description: Production server
security: []
paths:
  /api/v1/tts/sse:
    post:
      summary: TTS Stream
      operationId: tts_stream_api_v1_tts_sse_post
      parameters:
        - name: X-API-Key-ID
          in: header
          required: true
          schema:
            anyOf:
              - type: string
            title: X-Api-Key-Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TextToSpeechRequest'
      responses:
        '200':
          description: Successful Server-Sent Events stream
          content:
            text/event-stream:
              schema:
                type: string
              example: >-
                event: audio_chunk

                data:
                UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA=


                event: completed

                data: {"status": "success"}
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StandardErrorResponse'
              example:
                success: false
                error:
                  type: INVALID_REQUEST_ERROR
                  message: Invalid text or audio configuration.
        '429':
          description: Too Many Requests
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StandardErrorResponse'
              example:
                success: false
                error:
                  type: RATE_LIMIT_ERROR
                  message: Rate limit exceeded. Please try again later.
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StandardErrorResponse'
              example:
                success: false
                error:
                  type: API_ERROR
                  message: An unexpected error occurred while processing.
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StandardErrorResponse'
              example:
                success: false
                error:
                  type: SERVICE_UNAVAILABLE
                  message: Text-to-speech service is temporarily unavailable.
components:
  schemas:
    TextToSpeechRequest:
      properties:
        text:
          type: string
          title: Text
        voice:
          type: string
          title: Voice
          description: Voice name from the Timbre catalog.
        model:
          allOf:
            - $ref: '#/components/schemas/TTSModel'
        language:
          type: string
          title: Language
          description: >-
            Language code. Use `IND-IN` for Timbre v2.0. For Timbre v2.5 use
            `auto`, `hi-IN`, `en-IN`, `ta-IN`, `te-IN`, `kn-IN`, `ml-IN`,
            `mr-IN`, `pa-IN`, `bn-IN`, or `gu-IN`.
        speed:
          type: number
          title: Speed
          description: 'Playback speed multiplier (Timbre v2.5 only). Range: 0.85–1.15.'
        audio_config:
          allOf:
            - $ref: '#/components/schemas/AudioConfig'
      type: object
      required:
        - text
        - model
        - audio_config
      title: TextToSpeechRequest
      description: Request body for TTS inference.
      example:
        text: नमस्ते, आप कैसे हैं?
        voice: Pranav
        model: timbre-v2.5
        language: hi
        speed: 1
        audio_config:
          encoding: linear_pcm
          container: wav
          num_channels: 1
          sample_rate: 48000
          sample_width: 2
    StandardErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          $ref: '#/components/schemas/ErrorDetail'
    TTSModel:
      type: string
      enum:
        - timbre-v2.5
        - timbre-v2.0
      title: TTSModel
      description: Supported TTS models.
    AudioConfig:
      properties:
        sample_rate:
          type: integer
          maximum: 48000
          minimum: 8000
          title: Sample Rate
          description: >-
            Sample rate in Hz. Supported: 8000, 16000, 22050, 24000, 44100,
            48000
        num_channels:
          type: integer
          maximum: 8
          minimum: 1
          title: Num Channels
          description: Number of audio channels
        sample_width:
          type: integer
          maximum: 4
          minimum: 1
          title: Sample Width
          description: Sample width in bytes
        encoding:
          allOf:
            - $ref: '#/components/schemas/AudioEncoding'
          description: Audio encoding format
        container:
          allOf:
            - $ref: '#/components/schemas/AudioContainer'
          description: Audio container format
        bitrate:
          allOf:
            - $ref: '#/components/schemas/MP3Bitrate'
          description: MP3 bitrate (only used when container=mp3)
      type: object
      title: AudioConfig
      description: Audio output configuration.
    ErrorDetail:
      type: object
      properties:
        type:
          type: string
          description: A short error code string (e.g., 'INVALID_REQUEST_ERROR').
        message:
          type: string
          description: A descriptive error message.
    AudioEncoding:
      type: string
      enum:
        - linear_pcm
        - pcm_s16le
        - pcm_mulaw
        - pcm_alaw
        - oggopus
      title: AudioEncoding
      description: >-
        Supported audio encodings. Use pcm_mulaw or pcm_alaw for G.711 telephony
        codecs (forces 8000 Hz output). Use oggopus or set container=ogg to
        receive a playable OGG Opus file.
    AudioContainer:
      type: string
      enum:
        - raw
        - mp3
        - wav
        - mulaw
        - alaw
        - ogg
      title: AudioContainer
      description: Supported audio containers.
    MP3Bitrate:
      type: string
      enum:
        - 32k
        - 64k
        - 96k
        - 128k
        - 192k
      title: MP3Bitrate
      description: >-
        Supported MP3 bitrate options (only used when container is MP3).
        Default: 128k

````