> ## Documentation Index
> Fetch the complete documentation index at: https://heygen-1fa696a7.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# HeyGen Voice Speech

> Generate completed or streaming audio from a professional voice clone through the HeyGen Voice speech APIs.

<img className="w-full h-44 object-cover rounded-xl" src="https://mintcdn.com/heygen-1fa696a7/hfMXXwJzjE7vBSYZ/images/theme/research-2.webp?fit=max&auto=format&n=hfMXXwJzjE7vBSYZ&q=85&s=d6ee10585b27ddaf8137d6ed67791708" alt="" noZoom width="1400" height="788" data-path="images/theme/research-2.webp" />

<Warning>
  These APIs are in private preview. Your account must be enabled before using a professional voice clone.
</Warning>

The [HeyGen Voice](/docs/models/heygen-voice) speech APIs provide two ways to synthesize audio:

* `POST /v3/models/audio/tts` waits for generation to finish and returns one audio URL.
* `POST /v3/models/audio/tts/stream` returns ordered audio parts as Server-Sent Events (SSE).

Both endpoints use the same request shape. The supplied `voice_id` identifies the voice implementation; callers do not select a voice mode during synthesis. Currently, the voice must be an `ACTIVE` [professional voice clone](/docs/voices/professional-voice-clone) owned by the API key's workspace. To synthesize speech with a stock, designed, or instant-cloned voice, use [Third Party Speech](/docs/voices/speech).

Professional-voice synthesis costs 0.6 API credits per generated minute, billed by generated duration.

## Authentication

Send your HeyGen API key with every request:

```bash theme={null}
-H "X-Api-Key: $HEYGEN_API_KEY"
```

## Generate completed speech

`POST /v3/models/audio/tts` keeps the request open until synthesis and audio assembly complete.

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/models/audio/tts" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "voice_id": "0f4e5d8c9a1b4d62a914938d06c31234",
    "text": "Hello from my professional voice.",
    "language": "en",
    "seed": 7
  }'
```

```json Response theme={null}
{
  "data": {
    "audio_url": "https://files.heygen.ai/generated/model-speech.wav",
    "duration": 3.42
  }
}
```

The returned file is one complete mono PCM16 WAV at 44.1 kHz. No polling request is required.

### Response fields

| Field       | Type   | Description                    |
| ----------- | ------ | ------------------------------ |
| `audio_url` | string | URL of the completed WAV file. |
| `duration`  | number | Audio duration in seconds.     |

## Stream speech

`POST /v3/models/audio/tts/stream` returns `text/event-stream`. Disable response buffering and process each event as it arrives.

```bash theme={null}
curl -N --no-buffer -X POST "https://api.heygen.com/v3/models/audio/tts/stream" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "voice_id": "0f4e5d8c9a1b4d62a914938d06c31234",
    "text": "Hello from my professional voice.",
    "language": "en",
    "seed": 7,
    "with_timestamps": true
  }'
```

### Request fields

| Field             | Type    | Required | Default           | Description                                                                                          |
| ----------------- | ------- | -------- | ----------------- | ---------------------------------------------------------------------------------------------------- |
| `voice_id`        | string  | Yes      | —                 | An `ACTIVE` professional voice owned by the API key's workspace.                                     |
| `text`            | string  | Yes      | —                 | Plain text to synthesize, between 1 and 5,000 characters. SSML and `<break>` tags are not supported. |
| `language`        | string  | Yes      | —                 | Supported language code for synthesis, such as `en`.                                                 |
| `seed`            | integer | No       | provider-selected | Best-effort deterministic seed from `0` through `4294967295`.                                        |
| `with_timestamps` | boolean | No       | `false`           | Include word-timestamp events in the response stream. Streaming only.                                |

The completed endpoint accepts every field above except `with_timestamps`. Unknown fields are rejected.

### Audio events

Audio arrives as one or more indexed WAV parts:

```text theme={null}
data: {"type":"audio","part_index":0,"audio":"UklGR..."}

data: {"type":"audio","part_index":1,"audio":"UklGR..."}
```

Each `audio` value is a base64-encoded standalone WAV. Play parts in ascending `part_index` order. Do not concatenate the encoded WAV containers byte-for-byte.

### Timestamp events

When `with_timestamps` is `true`, the stream may include alignment events containing word-level timing:

```text theme={null}
data: {"type":"alignment","word_alignments":[{"text":"Hello","start_time":0.0,"end_time":0.42,"confidence":0.99}]}
```

Each alignment contains:

| Field        | Type   | Description                           |
| ------------ | ------ | ------------------------------------- |
| `text`       | string | Aligned word.                         |
| `start_time` | number | Start time in seconds.                |
| `end_time`   | number | End time in seconds.                  |
| `confidence` | number | Alignment confidence from `0` to `1`. |

### Stream completion and errors

A clean stream ends with:

```text theme={null}
data: [DONE]
```

If synthesis fails after streaming has started, the stream emits a sanitized terminal error and does not emit `[DONE]`:

```text theme={null}
data: {"type":"error","detail":"Voice inference failed mid-stream"}
```

Errors before the first stream event use the standard JSON HTTP error envelope.

## Errors

```json Error response theme={null}
{
  "error": {
    "code": "invalid_parameter",
    "message": "language is not a supported language.",
    "param": "language",
    "doc_url": "https://developers.heygen.com/docs/error-codes#invalid-parameter"
  }
}
```

| HTTP status | Error code               | Meaning                                                                                            |
| ----------- | ------------------------ | -------------------------------------------------------------------------------------------------- |
| `400`       | `invalid_parameter`      | A required field is missing, an unknown field was supplied, or text, language, or seed is invalid. |
| `401`       | `unauthorized`           | The API key is missing or invalid.                                                                 |
| `402`       | `insufficient_credit`    | The API credit balance is empty. Purchase additional credits before generating speech.             |
| `403`       | `forbidden`              | The account is not enabled for the private professional voice preview.                             |
| `403`       | `resource_access_denied` | The caller lacks API access.                                                                       |
| `404`       | `voice_not_found`        | The voice does not exist in the caller's workspace.                                                |
| `409`       | `voice_not_ready`        | Voice training is still pending.                                                                   |
| `409`       | `voice_training_failed`  | Voice training failed.                                                                             |
| `429`       | `rate_limit_exceeded`    | Retry after the number of seconds in the `Retry-After` header.                                     |
| `500`       | `internal_error`         | Synthesis failed unexpectedly. Provider details are not exposed.                                   |
| `503`       | `service_unavailable`    | Inference is temporarily busy and the request is safe to retry.                                    |

Each endpoint is limited to 30 requests per minute per workspace member.
