> ## 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 dialogue

> Generate one audio file of a conversation in which each line has its own ElevenLabs voice.

`POST /v1/audio/dialogue` turns an ordered list of lines into one audio file of a conversation. Each line names its own voice, so you can script an interview, a podcast intro, or a scene without stitching clips together. The response body is the audio file.

| Model | Price |
| - | - |
| [`eleven-v4-dialogue`](/api-manual/audio/eleven-v4-dialogue) | \$0.12 per 1,000 characters |
| [`eleven-v3-dialogue`](/api-manual/audio/eleven-v3-dialogue) | \$0.12 per 1,000 characters |

<ParamField body="model" type="string" required>
  `eleven-v4-dialogue` or `eleven-v3-dialogue`.
</ParamField>

<ParamField body="inputs" type="object[]" required>
  1 to 50 lines in speaking order. The text of all lines totals at most 2,000
  characters, and one dialogue uses at most 10 different voices.

  <Expandable title="line">
    <ParamField body="text" type="string" required>
      The line to speak. Blank text and control characters other than
      newlines are rejected.
    </ParamField>

    <ParamField body="voice" type="string" required>
      A voice ID or first name from the
      [voice list](/api-reference/audio-speech#voices).
    </ParamField>
  </Expandable>
</ParamField>

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

<ParamField body="language" type="string">
  An ISO 639 language code of two or three lowercase letters, such as `en`.
  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.
</ParamField>

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

Fields that aren't listed here return `invalid_request`.

## Direct the delivery

Lines can carry audio tags in square brackets, such as `[excited]` or
`[laughs]`, to shape how they're spoken. Tags are part of `text`, so they
count toward the 2,000-character total and are billed.

```json theme={null}
{
  "model": "eleven-v3-dialogue",
  "inputs": [
    { "text": "[excited] Did you see the launch?", "voice": "George" },
    { "text": "[laughs] I watched it twice!", "voice": "Sarah" }
  ]
}
```

## Response

A successful request returns HTTP `200` with the audio as the body. The
`Content-Type` matches `response_format`, for example `audio/mpeg`, and the
response carries `x-gateway-execution-id`.

## Billing

The request is billed per character across every line's `text`, counted in
Unicode code points. A full 2,000-character dialogue costs \$0.24. The price is
known before the provider is called, and failed requests aren't charged. This
endpoint rejects `Idempotency-Key`; if a request times out, check your Console
request logs before you retry.

## Errors

| Status | `error.code` | Cause |
| - | - | - |
| 400 | `invalid_request` | A field is unknown or invalid, the lines total more than 2,000 characters, the dialogue uses more than 10 voices, or a voice isn't in the list. |
| 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. |
| 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). |
| 503 | `no_eligible_route` | The model doesn't run on this endpoint, or no route is available right now. |

See [Errors](/errors) for rate limits and provider failures.

<RequestExample>
  ```bash Curl theme={null}
  curl https://api.snapgen.org/v1/audio/dialogue \
    -H "Authorization: Bearer $SNAPGEN_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "eleven-v4-dialogue",
      "inputs": [
        {
          "text": "[excited] Did you see the launch?",
          "voice": "JBFqnCBsd6RMkjVDRZzb"
        },
        {
          "text": "[laughs] I watched it twice!",
          "voice": "EXAVITQu4vr4xnSDxMaL"
        }
      ]
    }' \
    --output dialogue.mp3
  ```

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

  body = {
      "model": "eleven-v4-dialogue",
      "inputs": [
          {"text": "[excited] Did you see the launch?", "voice": "JBFqnCBsd6RMkjVDRZzb"},
          {"text": "[laughs] I watched it twice!", "voice": "EXAVITQu4vr4xnSDxMaL"},
      ],
  }
  request = Request(
      "https://api.snapgen.org/v1/audio/dialogue",
      data=json.dumps(body).encode(),
      headers={
          "Authorization": f"Bearer {os.environ['SNAPGEN_API_KEY']}",
          "Content-Type": "application/json",
      },
  )

  with urlopen(request) as response, open("dialogue.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/dialogue", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.SNAPGEN_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "eleven-v4-dialogue",
      inputs: [
        { text: "[excited] Did you see the launch?", voice: "JBFqnCBsd6RMkjVDRZzb" },
        { text: "[laughs] I watched it twice!", voice: "EXAVITQu4vr4xnSDxMaL" },
      ],
    }),
  });
  if (!response.ok) throw new Error(await response.text());
  await writeFile("dialogue.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": "inputs: dialogue text must total at most 2000 characters",
      "type": "invalid_request_error",
      "param": null,
      "code": "invalid_request"
    }
  }
  ```
</ResponseExample>
