> ## 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 Professional Clone

> Train a studio-grade professional voice clone from 20+ minutes of recordings on the HeyGen Voice model, then generate completed or streaming speech.

<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>
  Professional voice cloning is in private preview and is a **paid feature**. Each voice occupies a purchased professional voice clone slot. Buy slots on the [API usage page](https://app.heygen.com/developers/usage) before creating a voice; a request with no free slot returns `400 resource_limit_reached`.
</Warning>

A professional clone trains a dedicated [HeyGen Voice](/docs/models/heygen-voice) adapter from one or more recordings of the same speaker. It is the highest-fidelity clone HeyGen offers. To clone from a single short recording in minutes, use [HeyGen Instant Clone](/docs/voices/instant-voice-clone).

1. [Create a voice](#1-create-a-voice), or retrain an existing one with new recordings.
2. [Poll](#2-poll-training-status) until the voice is `ACTIVE`.
3. [Generate speech](#3-generate-speech), completed or streamed.

## Before you start

### Get private-preview access

Preview access is enabled per HeyGen username. [Create an API key](/docs/api-key) in the workspace that should own the voice, look up its username, and send that username to the Professional Voice Cloning preview team:

```bash theme={null}
curl -sS "https://api.heygen.com/v3/users/me" \
  -H "X-Api-Key: $HEYGEN_API_KEY" | jq -er '.data.username'
```

Until the account is enabled, the `/v3/models/audio` endpoints return `403 forbidden`. Voices belong to the workspace of the API key that created them.

### Slots and training allowance

* One purchased slot per voice. Retraining reuses the voice's slot.
* Each slot provides five pooled trainings per monthly billing period, initial training included. Failed trainings are free.
* If the workspace later exceeds its slot limit, for example when a slot add-on lapses, the surplus voices return `voice_expired` on synthesis until you add a slot or delete another professional voice. The voice and its data stay intact.

### Prepare the recordings

Provide 1–10 recordings of the same speaker totaling at least 20 minutes. Duration is measured including silence, so trim dead air, background noise, and overlapping speech. Upload local files with the [Assets API](/docs/upload-assets) and pass the returned `asset_id` values:

```bash theme={null}
ASSET_1=$(curl -sS -X POST "https://api.heygen.com/v3/assets" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -F "file=@./narrator-part-1.wav" | jq -er '.data.asset_id')
```

Size limits per recording: 32 MB for a public URL, 16 MB for inline base64 after decoding, 200 MB for a completed `asset_id`. For larger files use the [direct upload flow](/docs/upload-assets#upload-large-files-direct-upload).

## 1. Create a voice

`POST /v3/models/audio/voices` returns `202 Accepted` while training runs.

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/models/audio/voices" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: customer-voice-2026-08-22" \
  -d '{
    "mode": "professional",
    "name": "Customer narrator",
    "language": "en",
    "audio": [
      { "type": "asset_id", "asset_id": "'"$ASSET_1"'" },
      { "type": "asset_id", "asset_id": "'"$ASSET_2"'" }
    ]
  }'
```

```json Response theme={null}
{
  "data": {
    "voice_id": "0f4e5d8c9a1b4d62a914938d06c31234"
  }
}
```

| Field      | Type   | Required   | Description                                                                                                                              |
| ---------- | ------ | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `mode`     | string | New voices | `professional`.                                                                                                                          |
| `name`     | string | New voices | Display name, up to 256 characters.                                                                                                      |
| `language` | string | New voices | Primary language code of the recordings, such as `en`.                                                                                   |
| `audio`    | array  | Yes        | 1–10 recordings, each `{ "type": "url", "url" }`, `{ "type": "asset_id", "asset_id" }`, or `{ "type": "base64", "media_type", "data" }`. |
| `voice_id` | string | Retraining | Existing `ACTIVE` voice to retrain. Omit when creating.                                                                                  |

Every recording is validated and staged before the voice is created, so undecodable audio, an unreachable URL, or fewer than 20 minutes in total returns `400 invalid_parameter` with no `voice_id`.

`Idempotency-Key` is optional. Reusing a key within 24 hours returns the original response; a duplicate that arrives while the original is still being accepted returns `409 request_in_progress`. Without the header, repeated requests create separate voices.

### Retrain a voice

Send the existing `voice_id` with replacement `audio`. The ID, name, language, and mode are kept. The voice becomes `PENDING` until training completes, and a failed retraining restores the previously active voice.

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/models/audio/voices" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: customer-voice-retrain-2026-09-02" \
  -d '{
    "voice_id": "0f4e5d8c9a1b4d62a914938d06c31234",
    "audio": [
      { "type": "asset_id", "asset_id": "'"$ASSET_1"'" }
    ]
  }'
```

## 2. Poll training status

Poll `GET /v3/models/audio/voices/{voice_id}` with backoff until the status is terminal.

```bash theme={null}
curl "https://api.heygen.com/v3/models/audio/voices/0f4e5d8c9a1b4d62a914938d06c31234" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

```json Response theme={null}
{
  "data": {
    "voice_id": "0f4e5d8c9a1b4d62a914938d06c31234",
    "mode": "professional",
    "name": "Customer narrator",
    "language": "en",
    "status": "ACTIVE",
    "created_at": 1787405696
  }
}
```

| Status    | Meaning                                                                                                                                                                      |
| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PENDING` | Training is queued or running.                                                                                                                                               |
| `ACTIVE`  | Ready for speech generation.                                                                                                                                                 |
| `FAILED`  | Training ended. `failure_reason` is one of `INVALID_AUDIO`, `INSUFFICIENT_AUDIO`, `PREPROCESSING_FAILED`, `TRAINING_FAILED`, `ARTIFACT_VALIDATION_FAILED`, `INTERNAL_ERROR`. |

`created_at` is a Unix timestamp in seconds.

## 3. Generate speech

Pass the `ACTIVE` voice to [HeyGen Voice Speech](/docs/voices/heygen-voice-speech): `POST /v3/models/audio/tts` for one completed WAV, or `POST /v3/models/audio/tts/stream` for audio parts as they are generated.

```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 clone.",
    "language": "en"
  }'
```

## Manage voices

`GET /v3/models/audio/voices` lists the workspace's professional voices, newest first, with `limit` (1–100, default 10) and cursor `token`. Pass the returned `next_token` while `has_more` is `true`.

`DELETE /v3/models/audio/voices/{voice_id}` removes an `ACTIVE` or `FAILED` voice and frees its slot. Wait for a `PENDING` voice to finish training first.

```bash theme={null}
curl -X DELETE "https://api.heygen.com/v3/models/audio/voices/0f4e5d8c9a1b4d62a914938d06c31234" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

## Errors

| HTTP status | Error code               | Meaning                                                                                |
| ----------- | ------------------------ | -------------------------------------------------------------------------------------- |
| `400`       | `invalid_parameter`      | Invalid request or audio input, or under 20 minutes of recordings.                     |
| `400`       | `resource_limit_reached` | No free voice slot, or the monthly training allowance is used up.                      |
| `403`       | `forbidden`              | The account is not enabled for the preview.                                            |
| `409`       | `request_in_progress`    | The same `Idempotency-Key` is still being accepted. Retry with backoff.                |
| `409`       | `resource_not_ready`     | The voice is `PENDING`: another training is running, or it was submitted for deletion. |
| `429`       | `rate_limit_exceeded`    | Retry after the seconds in `Retry-After`.                                              |

Synthesis errors, including `voice_expired`, are listed on [HeyGen Voice Speech](/docs/voices/heygen-voice-speech#errors). The full catalog is in [Error Codes](/docs/error-codes).
