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

# Speech to Speech

> Convert a recording into an instant voice. Keep the words and timing.

`POST /v3/models/audio/sts` converts a recording into a voice from your workspace.
The words and timing stay the same. The response contains a WAV URL and its duration.

`voice_id` must be an `ACTIVE` [instant voice](/docs/voices/heygen-voice-instant-clone) in your workspace. Professional voice clones are not supported yet. Each workspace member can send 30 requests per minute.

## Authentication

Use an API key with the `voices:write` permission, or an OAuth bearer token.
Send the API key in `X-Api-Key` or `Authorization: Bearer`.
Send an OAuth token in `Authorization: Bearer`. OAuth requires a paid plan and a role that permits API access.

## Request fields

| Field | Type | Required | Description |
| - | - | - | - |
| `voice_id` | string | Yes | An `ACTIVE` instant voice owned by the authenticated workspace. |
| `audio` | object | Yes | The recording to convert: `{ "type": "asset_id", "asset_id" }`, `{ "type": "url", "url" }`, or `{ "type": "base64", "media_type", "data" }`. |
| `remove_background_noise` | boolean | No | Clean the recording before conversion. Default `false`. This adds latency. |
| `seed` | integer | No | A value from `0` through `4294967295`. Requests best-effort repeatable generation. |
| `model_id` | string | No | The conversion model. The only supported value and default is `heygen-voice-sts-0`. |

About the recording:

* It can be up to 300 seconds long.
* It can be up to 100 MB as an [uploaded asset](/docs/upload-assets), 32 MB by URL, or 16 MB as inline base64.
* WAV, MP3, FLAC, OGG, M4A, and AAC work. For inline base64, set `media_type`, such as `audio/wav` or `audio/mpeg`.
* A URL must be public HTTPS, point at the file itself, and download within 60 seconds.
* Send clear speech. A recording that can't be read or converted returns `400` with `param` set to `audio`.

Unknown fields and invalid values return `400 invalid_parameter`, with `param` set to that field.

## Convert speech

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/models/audio/sts" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: sts-example-001" \
  -d '{
    "voice_id": "7c2a9e4f1b3d4e6a8f0c2d4e6a8b1234",
    "audio": { "type": "url", "url": "https://example.com/recording.mp3" }
  }'
```

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

Conversion can take 150 seconds. No polling is needed.
Set your client timeout to at least 160 seconds.
`duration` is in seconds and matches the recording.
Successful responses include `X-Request-Id`; use it to find usage records.

The first request can take longer while HeyGen prepares the voice.
If preparation takes too long, the request returns `409 voice_not_ready`.
Retry after the delay in `Retry-After`.

## Retries and disconnects

Send the optional `Idempotency-Key` header to retry a request safely.
The key must contain 1–255 characters from `A–Z`, `a–z`, `0–9`, `_`, `-`, `:`, and `.`.
Use a UUID or another unique value for each new conversion.

Keys are scoped to the workspace and this endpoint.
A retry with the same key and body returns the completed result without another charge for 24 hours.
A different body with the same key returns `409 conflict`.
A retry while the first request runs returns `409 request_in_progress`. Wait for the `Retry-After` delay.

With a key, conversion continues after a client disconnect and can still be charged.
Without a key, a disconnect before the charge cancels the request without a charge.
After `504 gateway_timeout`, wait before retrying with the same key. The conversion can still be running.

## Errors

| HTTP status | Error code | Meaning |
| - | - | - |
| `400` | `invalid_parameter` | Missing or unknown field, or an invalid value. `param` is `audio` for a recording that is longer than 300 seconds, too large, empty, or can't be read. `param` is `voice_id` for a professional voice clone. |
| `401` | `unauthorized` | The API key or OAuth token is missing or invalid. |
| `402` | `insufficient_credit` | The selected credit balance does not cover the recording's length. |
| `402` | `plan_upgrade_required` | OAuth requires a paid plan. |
| `403` | `insufficient_api_key_scope` | The API key does not have the `voices:write` permission. |
| `403` | `resource_access_denied` | The workspace role does not permit API access. |
| `404` | `voice_not_found` | The voice is not in the caller's workspace. |
| `409` | `voice_not_ready` | The voice is still being created or prepared. Retry after the seconds in `Retry-After`. |
| `409` | `voice_training_failed` | The voice is `FAILED`. Don't retry; use another voice. |
| `409` | `request_in_progress` | A request with this key is running. Wait for the `Retry-After` delay. |
| `409` | `conflict` | The key was used with a different body. Use a new key for a new conversion. |
| `429` | `rate_limit_exceeded` | Retry after the seconds in `Retry-After`. |
| `500` | `internal_error` | The conversion failed. |
| `503` | `service_unavailable` | Speech to speech is busy, or the recording's URL or asset did not download in time. Retry after the seconds in `Retry-After`. |
| `504` | `gateway_timeout` | The conversion did not finish within 150 seconds. It may still be running, so wait before you retry. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.