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

# Voices

> Text-to-speech with Atlas's fine-tuned voices.

## Overview

Every Atlas voice is served two ways: a one-shot **HTTP endpoint** (`POST /v1/audio/speech`, OpenAI-compatible) and a **WebSocket stream** that returns audio sentence-by-sentence. Use the WebSocket service for interactive, real-time applications; use HTTP when you want a complete audio file per request.

<CardGroup cols={2}>
  <Card title="HTTP endpoint reference" icon="globe" href="/api-reference/speech">
    Full request/response reference for `POST /v1/audio/speech`.
  </Card>

  <Card title="Streaming reference" icon="bolt" href="/api-reference/streaming">
    The WebSocket frame protocol for sentence-by-sentence audio.
  </Card>
</CardGroup>

## Prerequisites

### Account setup

1. Sign in to the [Atlas playground](https://sabi-tts-app.dev.neuralace.co).
2. Open **API keys** and create a key — the `sk_…` plaintext is shown only once.

### Required environment variables

```bash theme={null}
ATLAS_API_KEY=sk_...                                  # your secret API key
ATLAS_BASE_URL=https://api.tts.runatlas.com      # gateway base URL
```

<Warning>
  Your `sk_` key is a secret. Send it only from your server — never ship it in client-side code. Keys are stored hashed on our side and cannot be recovered, only rotated.
</Warning>

## Configuration

### Request parameters

<ParamField path="voice" type="string" required>
  The voice id, e.g. `lylla`. List available voices via [`/v1/models`](/api-reference/models).
</ParamField>

<ParamField path="input" type="string" required>
  The text to speak.
</ParamField>

<ParamField path="response_format" default="wav" type="string">
  Output audio format: `wav`, `mp3`, `pcm`, `opus`, or `flac`. With `pcm` the HTTP response is streamed as it is synthesized.
</ParamField>

<ParamField path="model" type="string">
  Accepted for OpenAI SDK compatibility but **ignored** — the voice selects the model. Pass any placeholder (e.g. `"atlas-tts"`).
</ParamField>

### Response headers

| Header          | Meaning                                                                |
| --------------- | ---------------------------------------------------------------------- |
| `x-upstream-ms` | Time spent in model inference for this request.                        |
| `x-gateway-ms`  | Total gateway time. `x-gateway-ms − x-upstream-ms` = gateway overhead. |

## Usage

### Generate a clip (HTTP)

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  import os

  client = OpenAI(
      base_url="https://api.tts.runatlas.com/v1",
      api_key=os.environ["ATLAS_API_KEY"],
  )

  with client.audio.speech.with_streaming_response.create(
      model="atlas-tts",
      voice="lylla",
      input="Hello from Lylla.",
      response_format="wav",
  ) as resp:
      resp.stream_to_file("out.wav")
  ```

  ```typescript Node theme={null}
  import OpenAI from "openai";
  import fs from "node:fs";

  const client = new OpenAI({
    baseURL: "https://api.tts.runatlas.com/v1",
    apiKey: process.env.ATLAS_API_KEY,
  });

  const res = await client.audio.speech.create({
    model: "atlas-tts",
    voice: "lylla",
    input: "Hello from Lylla.",
    response_format: "wav",
  });
  fs.writeFileSync("out.wav", Buffer.from(await res.arrayBuffer()));
  ```
</CodeGroup>

### Stream sentence-by-sentence (WebSocket)

```python Python theme={null}
# pip install websockets
import asyncio, json, os, websockets

async def main():
    url = "wss://api.tts.runatlas.com/v1/audio/speech/stream"
    headers = [("Authorization", "Bearer " + os.environ["ATLAS_API_KEY"])]
    async with websockets.connect(url, additional_headers=headers) as ws:
        await ws.send(json.dumps({"type": "start", "voice": "lylla", "response_format": "wav"}))
        idx = 0
        async for msg in ws:
            if isinstance(msg, (bytes, bytearray)):       # per-sentence audio frame
                open(f"sentence_{idx}.wav", "wb").write(msg); idx += 1
                continue
            evt = json.loads(msg)
            if evt["type"] == "ready":
                await ws.send(json.dumps({"type": "text", "text": "Hello. This streams sentence by sentence."}))
                await ws.send(json.dumps({"type": "done"}))
            elif evt["type"] == "session.done":
                break

asyncio.run(main())
```

## Notes

* The standard catalogue is **English**; Hindi voices are available to enterprise accounts — [contact us](mailto:support@runatlas.com) for access.
* Hindi voices accept **Devanagari or romanized Hindi (Hinglish)** — `"Kya haal hai?"` and `"क्या हाल है?"` both work; romanized input is transliterated before synthesis.
* The WebSocket service emits **one binary audio frame per sentence** — begin playback on the first frame for the lowest perceived latency.
* Usage is metered per account in **characters per day**, with a per-minute request rate limit. `429` responses carry a `quota_error` body — see [Errors](/api-reference/errors).
* The `model` request field is ignored; the `voice` is the sole selector.
