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

# Audio to Video

> Bring your own audio — a voice memo, a podcast segment, a dubbed track — and lip-sync it onto your avatar, digital twin, or any image with one HeyGen API call.

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

## Overview

Audio to Video turns a recorded audio track into a talking video: you supply the audio, pick who says it, and HeyGen handles the lip-sync and render. It's the same [`POST /v3/videos`](/reference/create-video) endpoint used for script-driven videos — the difference is that you pass `audio_url` (or `audio_asset_id`) instead of `script`, and the video's length follows your audio.

Two subject choices, both accepting the same audio fields:

| `type`   | Subject                                                                        | You provide                        |
| -------- | ------------------------------------------------------------------------------ | ---------------------------------- |
| `avatar` | An avatar you already have — digital twin, studio avatar, or photo avatar look | `avatar_id`                        |
| `image`  | Any single-person image, animated on the fly                                   | `image` (URL, asset ID, or base64) |

Use it when the voice already exists: preserving a real person's recorded voice on their digital twin, dubbing localized audio onto one presenter, or lip-syncing audio produced by another tool.

## Quick Example

Lip-sync an audio file onto an avatar:

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/videos" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "avatar",
    "avatar_id": "YOUR_AVATAR_ID",
    "audio_url": "https://example.com/narration.mp3",
    "title": "Audio to video — narration",
    "aspect_ratio": "auto",
    "resolution": "1080p"
  }'
```

```json Response theme={null}
{
  "data": {
    "video_id": "4086e92fc7a54d67b62ef93b1ccf53db",
    "status": "waiting",
    "output_format": "mp4"
  }
}
```

Generation is asynchronous. Poll [`GET /v3/videos/{video_id}`](/reference/get-video) until `status` is `completed`, then download `video_url` — or pass a `callback_url` to receive a [webhook](/docs/webhooks) instead.

## Audio Sources

Provide exactly one audio source per request — audio fields are mutually exclusive with `script`:

| Field            | What it takes                                                                                                   |
| ---------------- | --------------------------------------------------------------------------------------------------------------- |
| `audio_url`      | Public HTTPS URL of an audio file.                                                                              |
| `audio_asset_id` | Asset ID of an uploaded audio file (MP3 or WAV, max 32 MB) — from [`POST /v3/assets`](/reference/upload-asset). |

<Tip>
  Have text and a voice instead of a recording? Two options: pass `script` + `voice_id` directly (skip the audio step entirely), or synthesize audio first with [`POST /v3/voices/speech`](/reference/generate-speech) — its response `audio_url` can be passed straight into `audio_url` here. The TTS route is handy when you want to reuse the same generated narration across several videos or archive it separately.
</Tip>

## With an Avatar or Digital Twin

`"type": "avatar"` works with any avatar ID you own — a [digital twin](/generate-avatar-video) trained from real footage, a studio avatar, or a [photo avatar](/photo-avatar) look.

```json theme={null}
{
  "type": "avatar",
  "avatar_id": "YOUR_AVATAR_ID",
  "audio_asset_id": "YOUR_AUDIO_ASSET_ID",
  "background": { "type": "color", "value": "#0b1220" }
}
```

| Parameter                      | Type    | Required     | Description                                                                                                                                                 |
| ------------------------------ | ------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                         | string  | Yes          | Must be `avatar`.                                                                                                                                           |
| `avatar_id`                    | string  | Yes          | Video avatar or photo avatar look ID. Browse with [`GET /v3/avatars/looks`](/reference/list-avatar-looks).                                                  |
| `audio_url` / `audio_asset_id` | string  | One required | The audio to lip-sync — see [Audio Sources](#audio-sources).                                                                                                |
| `engine`                       | object  | No           | Defaults to [Avatar IV](/avatar-iv). Pass `{ "type": "avatar_v" }` for [Avatar V](/avatar-v) on eligible looks (check `supported_api_engines` on the look). |
| `motion_prompt`                | string  | No           | Natural-language body-motion and gesture control. Photo avatars on either engine; video avatars on Avatar V.                                                |
| `expressiveness`               | string  | No           | Expressiveness level for photo avatars on Avatar IV. Defaults to `low`.                                                                                     |
| `background`                   | object  | No           | Background behind the avatar: `{ "type": "color", "value": "#RRGGBB" }` for a solid color, or `{ "type": "image", ... }` with a `url` or `asset_id`.        |
| `remove_background`            | boolean | No           | Remove the avatar background (video avatars must be trained with matting enabled).                                                                          |
| `output_format`                | string  | No           | `mp4` (default) or `webm` for a transparent background — see [Transparent Background Videos](/transparent-background-videos).                               |

## With an Image

`"type": "image"` animates any single-person image with lip-sync to your audio — no avatar creation step. It's [Image to Video](/image-to-video) with your own soundtrack.

```json theme={null}
{
  "type": "image",
  "image": { "type": "asset_id", "asset_id": "YOUR_IMAGE_ASSET_ID" },
  "audio_url": "https://example.com/narration.mp3"
}
```

| Parameter                      | Type   | Required     | Description                                                                                                                                                            |
| ------------------------------ | ------ | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                         | string | Yes          | Must be `image`.                                                                                                                                                       |
| `image`                        | object | Yes          | Image to animate: `{ "type": "url", "url": "..." }`, `{ "type": "asset_id", "asset_id": "..." }`, or `{ "type": "base64", "media_type": "image/png", "data": "..." }`. |
| `audio_url` / `audio_asset_id` | string | One required | The audio to lip-sync — see [Audio Sources](#audio-sources).                                                                                                           |
| `motion_prompt`                | string | No           | Natural-language body-motion control.                                                                                                                                  |
| `expressiveness`               | string | No           | Expressiveness level. Defaults to `low`.                                                                                                                               |

## Output Settings

Both subject types share the same output controls:

| Parameter      | Type   | Default | Description                                                                                                                              |
| -------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `title`        | string | —       | Display title in the HeyGen dashboard.                                                                                                   |
| `aspect_ratio` | string | `16:9`  | `16:9`, `9:16`, `4:5`, `5:4`, `1:1`, or `auto` (preserves the source's aspect ratio — recommended).                                      |
| `resolution`   | string | —       | `720p`, `1080p`, or `4k`.                                                                                                                |
| `fit`          | string | —       | How the subject fills the canvas: `cover` (fill, may crop) or `contain` (fit entirely, may show background).                             |
| `caption`      | object | —       | Caption settings. A sidecar subtitle file is returned via `subtitle_url`; add `"style": "default"` to also burn captions into the video. |
| `callback_url` | string | —       | [Webhook](/docs/webhooks) URL notified when the video is ready.                                                                          |
| `callback_id`  | string | —       | Caller-defined identifier echoed back in the webhook payload.                                                                            |

## Full Example

Record-to-video in one script: upload the audio, lip-sync it onto an avatar, and wait for the result.

```python theme={null}
import time
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.heygen.com"
HEADERS = {"x-api-key": API_KEY}


def audio_to_video(audio_path, avatar_id):
    """Upload an audio file, lip-sync it onto an avatar, return the video URL."""
    with open(audio_path, "rb") as f:
        asset = requests.post(
            f"{BASE}/v3/assets", headers=HEADERS, files={"file": f}
        ).json()["data"]

    video_id = requests.post(
        f"{BASE}/v3/videos",
        headers={**HEADERS, "Content-Type": "application/json"},
        json={
            "type": "avatar",
            "avatar_id": avatar_id,
            "audio_asset_id": asset["id"],
            "aspect_ratio": "auto",
            "resolution": "1080p",
        },
    ).json()["data"]["video_id"]

    while True:
        video = requests.get(f"{BASE}/v3/videos/{video_id}", headers=HEADERS).json()["data"]
        if video["status"] in ("completed", "failed"):
            break
        time.sleep(10)

    if video["status"] == "failed":
        raise RuntimeError(video.get("failure_message") or "video generation failed")
    return video["video_url"]


print(audio_to_video("narration.mp3", "YOUR_AVATAR_ID"))
```

Swap the `json` payload for the [`image` shape](#with-an-image) to drive the same pipeline from a photo instead of an avatar.
