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

# Text to speech

> Turn text into speech with ElevenLabs voices through the OpenAI-compatible speech endpoint.

`POST /v1/audio/speech` turns text into speech and returns the audio file as the response body. It accepts the OpenAI speech request (`model`, `input`, `voice`, `response_format`, and `speed`) and adds ElevenLabs voice settings. Choose a model from **Audio Series > ElevenLabs Speech**.

| Model | Characters per request | Price |
| - | - | - |
| [`eleven-v4`](/api-manual/audio/eleven-v4) | Up to 10,000 | \$0.12 per 1,000 characters |
| [`eleven-v3`](/api-manual/audio/eleven-v3) | Up to 5,000 | \$0.12 per 1,000 characters |
| [`eleven-multilingual-v2`](/api-manual/audio/eleven-multilingual-v2) | Up to 10,000 | \$0.12 per 1,000 characters |
| [`eleven-flash-v2.5`](/api-manual/audio/eleven-flash-v2-5) | Up to 40,000 | \$0.06 per 1,000 characters |

For a conversation between several voices in one file, use [Text to dialogue](/api-reference/audio-dialogue).

<ParamField body="model" type="string" required>
  One of the speech models above.
</ParamField>

<ParamField body="input" type="string" required>
  The text to speak, up to the model's character limit. Newlines are allowed;
  blank text and other control characters are rejected. Each character is
  billed.
</ParamField>

<ParamField body="voice" type="string" required>
  A voice ID or first name from the [voice list](#voices), for example
  `JBFqnCBsd6RMkjVDRZzb` or `George`. Names are case-insensitive. OpenAI voice
  names such as `alloy` aren't available.
</ParamField>

<ParamField body="response_format" type="string" default="mp3">
  `mp3`, `opus`, `pcm`, or `wav`. See [Output formats](#output-formats).
</ParamField>

<ParamField body="speed" type="number">
  Speaking speed, from `0.7` to `1.2`.
</ParamField>

<ParamField body="language" type="string">
  An ISO 639 language code of two or three lowercase letters, such as `en` or
  `de`. The provider rejects a code the model doesn't support.
</ParamField>

<ParamField body="stability" type="number">
  From `0` to `1`. Lower values give a broader emotional range; higher values
  sound more consistent from one generation to the next.
</ParamField>

<ParamField body="similarity_boost" type="number">
  From `0` to `1`. How closely the output follows the original voice.
</ParamField>

<ParamField body="style" type="number">
  From `0` to `1`. Exaggerates the voice's speaking style.
</ParamField>

<ParamField body="use_speaker_boost" type="boolean">
  Boosts similarity to the original speaker.
</ParamField>

<ParamField body="seed" type="integer">
  From `0` to `4294967295`. Makes repeated requests more repeatable, without
  guaranteeing identical audio.
</ParamField>

<ParamField body="previous_text" type="string">
  Up to 5,000 characters that come before `input`. Send it when you split long
  text across requests so the speech flows across the join. Not billed.
</ParamField>

<ParamField body="next_text" type="string">
  Up to 5,000 characters that follow `input`, for the same purpose. Not billed.
</ParamField>

<ParamField body="apply_text_normalization" type="string">
  `auto`, `on`, or `off`: whether numbers, dates, and similar text are spelled
  out before they're spoken.
</ParamField>

The body is validated strictly. A field that isn't listed here, including
OpenAI's `instructions`, returns `invalid_request`.

## Response

A successful request returns HTTP `200` with the audio as the body. The gateway
streams it to you as the provider sends it; save the body to a file.

| Header | Value |
| - | - |
| `Content-Type` | The type of the requested `response_format`, for example `audio/mpeg` |
| `Cache-Control` | `no-store` |
| `x-gateway-execution-id` | The execution ID. Quote it when you contact support. |

## Output formats

| `response_format` | Encoding | `Content-Type` |
| - | - | - |
| `mp3` (default) | MP3, 44.1 kHz, 128 kbps | `audio/mpeg` |
| `opus` | Opus, 48 kHz, 128 kbps | `audio/ogg` |
| `pcm` | Raw 16-bit PCM, 24 kHz, no header | `audio/pcm` |
| `wav` | WAV, 44.1 kHz | `audio/wav` |

## Voices

Every speech, dialogue, and voice changer model uses the same 21 ElevenLabs
premade voices. Send the voice ID or the first name as `voice`. Other
ElevenLabs voices, such as cloned or library voices, aren't available.

| Name | `voice` ID | Gender | Accent | Description | Preview |
| - | - | - | - | - | - |
| Adam | `pNInz6obpgDQGcFmaJgB` | Male | American | Dominant, Firm | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/pNInz6obpgDQGcFmaJgB/d6905d7a-dd26-4187-bfff-1bd3a5ea7cac.mp3) |
| Alice | `Xb7hH8MSUJpSbSDYk0k2` | Female | British | Clear, Engaging Educator | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3) |
| Bella | `hpp4J3VqNfWAUOO0d1Us` | Female | American | Professional, Bright, Warm | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/hpp4J3VqNfWAUOO0d1Us/dab0f5ba-3aa4-48a8-9fad-f138fea1126d.mp3) |
| Bill | `pqHfZKP75CvOlQylNhV4` | Male | American | Wise, Mature, Balanced | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3) |
| Brian | `nPczCjzI2devNBz1zQrb` | Male | American | Deep, Resonant and Comforting | |
| Callum | `N2lVS1w4EtoT3dr4eOWO` | Male | American | Husky Trickster | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3) |
| Charlie | `IKne3meq5aSn9XLyUdCD` | Male | Australian | Deep, Confident, Energetic | |
| Chris | `iP95p4xoKVk53GoZ742B` | Male | American | Charming, Down-to-Earth | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3) |
| Daniel | `onwK4e9ZLuTAKqWW03F9` | Male | British | Steady Broadcaster | |
| Eric | `cjVigY5qzO86Huf0OWal` | Male | American | Smooth, Trustworthy | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3) |
| George | `JBFqnCBsd6RMkjVDRZzb` | Male | British | Warm, Captivating Storyteller | |
| Harry | `SOYHLrjzK2X1ezoPC6cr` | Male | American | Fierce Warrior | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/SOYHLrjzK2X1ezoPC6cr/86d178f6-f4b6-4e0e-85be-3de19f490794.mp3) |
| Jessica | `cgSgspJ2msm6clMCkdW9` | Female | American | Playful, Bright, Warm | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3) |
| Laura | `FGY2WhTYpPnrIDTdsKH5` | Female | American | Enthusiast, Quirky Attitude | |
| Liam | `TX3LPaxmHKxFdv7VOQHJ` | Male | American | Energetic, Social Media Creator | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3) |
| Lily | `pFZP5JQG7iQjIQuC4Bku` | Female | British | Velvety Actress | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3) |
| Matilda | `XrExE9yKIg1WjnnlVkGX` | Female | American | Knowledgable, Professional | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3) |
| River | `SAz9YHcvj6GT2YYXdXww` | Neutral | American | Relaxed, Neutral, Informative | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3) |
| Roger | `CwhRBWXzGAHq8TQ4Fs17` | Male | American | Laid-Back, Casual, Resonant | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/CwhRBWXzGAHq8TQ4Fs17/58ee3ff5-f6f2-4628-93b8-e38eb31806b0.mp3) |
| Sarah | `EXAVITQu4vr4xnSDxMaL` | Female | American | Mature, Reassuring, Confident | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/EXAVITQu4vr4xnSDxMaL/01a3e33c-6e99-4ee7-8543-ff2216a32186.mp3) |
| Will | `bIHbv24MWmeRgasZH58o` | Male | American | Relaxed Optimist | [Listen](https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3) |

## Use the OpenAI SDK

The official OpenAI SDKs work with the SnapGen base URL. Pass a voice from the
list above. In Python, send ElevenLabs fields such as `stability` through
`extra_body`.

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

  from openai import OpenAI

  client = OpenAI(
      api_key=os.environ["SNAPGEN_API_KEY"],
      base_url="https://api.snapgen.org/v1",
  )

  with client.audio.speech.with_streaming_response.create(
      model="eleven-v4",
      voice="George",
      input="Welcome back! Today we explore the northern lights.",
      response_format="mp3",
      extra_body={"stability": 0.5},
  ) as response:
      response.stream_to_file("speech.mp3")
  ```

  ```javascript Node.js theme={null}
  const fs = require("node:fs");
  const OpenAI = require("openai");

  async function main() {
    const client = new OpenAI({
      apiKey: process.env.SNAPGEN_API_KEY,
      baseURL: "https://api.snapgen.org/v1",
    });

    const response = await client.audio.speech.create({
      model: "eleven-v4",
      voice: "George",
      input: "Welcome back! Today we explore the northern lights.",
      response_format: "mp3",
    });

    fs.writeFileSync("speech.mp3", Buffer.from(await response.arrayBuffer()));
  }

  main();
  ```
</CodeGroup>

## Billing

The request is billed per character of `input`, counted in Unicode code points:
`Héllo 👋` is 7 characters. `previous_text` and `next_text` are free. The
gateway prices the request before it calls the provider, so the charge is
known up front, and a failed request isn't charged. For example, 1,000
characters cost \$0.12 on `eleven-v4` and \$0.06 on `eleven-flash-v2.5`.

<Note>
  This endpoint is synchronous and rejects `Idempotency-Key`. If a request
  times out, the audio may already have been generated: check your Console
  request logs before you send it again.
</Note>

## Errors

Errors use the [standard error envelope](/errors).

| Status | `error.code` | Cause |
| - | - | - |
| 400 | `invalid_request` | A field is unknown or out of range, or `voice` isn't in the voice list. The message names the field. |
| 400 | `invalid_input` | `input` is missing or empty. |
| 400 | `input_too_long` | `input` has more characters than the model accepts. |
| 400 | `invalid_content_type` | The body isn't sent as `application/json`. |
| 400 | `idempotency_not_supported` | The request has an `Idempotency-Key` header. |
| 400 | `provider_rejected_request` | The provider refused the request, for example a `language` the model doesn't support. |
| 402 | `insufficient_funds` | Your balance can't cover the request. |
| 404 | `model_not_available` | The model ID is unknown or disabled. A key whose allowlist excludes the model gets `api_key_model_not_allowed` (403). |
| 429 | `rate_limit_exceeded`, `provider_rate_limited` | Too many requests. Wait for `Retry-After`, then back off. |
| 502 | `provider_http_error`, `provider_timeout` | The provider failed. Retry later. |
| 503 | `no_eligible_route`, `provider_unavailable` | The model doesn't run on this endpoint, or no route is available right now. |

<RequestExample>
  ```bash Curl theme={null}
  curl https://api.snapgen.org/v1/audio/speech \
    -H "Authorization: Bearer $SNAPGEN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "eleven-v4",
      "input": "Welcome back! Today we explore the northern lights.",
      "voice": "JBFqnCBsd6RMkjVDRZzb",
      "response_format": "mp3"
    }' \
    --output speech.mp3
  ```

  ```python Python theme={null}
  import json
  import os
  from urllib.request import Request, urlopen

  request = Request(
      "https://api.snapgen.org/v1/audio/speech",
      data=json.dumps({
          "model": "eleven-v4",
          "input": "Welcome back! Today we explore the northern lights.",
          "voice": "JBFqnCBsd6RMkjVDRZzb",
          "response_format": "mp3",
      }).encode(),
      headers={
          "Authorization": f"Bearer {os.environ['SNAPGEN_API_KEY']}",
          "Content-Type": "application/json",
      },
  )

  with urlopen(request) as response, open("speech.mp3", "wb") as file:
      file.write(response.read())
  ```

  ```javascript Node.js theme={null}
  import { writeFile } from "node:fs/promises";

  const response = await fetch("https://api.snapgen.org/v1/audio/speech", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SNAPGEN_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "eleven-v4",
      input: "Welcome back! Today we explore the northern lights.",
      voice: "JBFqnCBsd6RMkjVDRZzb",
      response_format: "mp3",
    }),
  });
  if (!response.ok) throw new Error(await response.text());
  await writeFile("speech.mp3", Buffer.from(await response.arrayBuffer()));
  ```
</RequestExample>

<ResponseExample>
  ```text 200 theme={null}
  HTTP/1.1 200 OK
  content-type: audio/mpeg
  cache-control: no-store
  x-gateway-execution-id: 5b1e9f3a-2c4d-4e6f-8a7b-9c0d1e2f3a4b

  <binary MP3 audio>
  ```

  ```json 400 theme={null}
  {
    "error": {
      "message": "voice: must be one of the listed voice IDs or names",
      "type": "invalid_request_error",
      "param": null,
      "code": "invalid_request"
    }
  }
  ```
</ResponseExample>
