Prerequisites
A portrait photo (PNG or JPEG) — clear, front-facing, good lighting
A voice_id for the voice you want. Use GET /v3/voices to browse options.
Step 1 — Create a Photo Avatar
Upload your photo and create a Photo Avatar with POST /v3/avatars:
curl -X POST "https://api.heygen.com/v3/avatars" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "photo",
"name": "Sarah — Marketing",
"file": {
"type": "url",
"url": "https://example.com/portrait.jpg"
}
}'
First upload the image via POST /v3/assets, then reference the returned asset_id:# Upload the image
curl -X POST "https://api.heygen.com/v3/assets" \
-H "x-api-key: YOUR_API_KEY" \
-F "file=@portrait.jpg"
# Create the avatar
curl -X POST "https://api.heygen.com/v3/avatars" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "photo",
"name": "Sarah — Marketing",
"file": {
"type": "asset_id",
"asset_id": "RETURNED_ASSET_ID"
}
}'
The response includes an avatar_item with an id — this is your avatar_id for video creation.
Step 2 — Generate the video
Use POST /v3/videos with the Photo Avatar ID:
curl -X POST "https://api.heygen.com/v3/videos" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"avatar_id": "YOUR_PHOTO_AVATAR_ID",
"script": "Hi there! This video was created from a single photo using the HeyGen API.",
"voice_id": "YOUR_VOICE_ID",
"title": "Photo Avatar Demo",
"resolution": "1080p",
"aspect_ratio": "16:9"
}'
Step 3 — Poll for completion
Video generation is asynchronous. Poll until status reaches completed:
curl -X GET "https://api.heygen.com/v3/videos/YOUR_VIDEO_ID" \
-H "x-api-key: YOUR_API_KEY"
| Status | Meaning |
|---|
pending | Queued for processing |
processing | Video is being generated |
completed | Ready — video_url is available |
failed | Something went wrong |
Full example
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE = "https://api.heygen.com"
HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}
# 1. Create a Photo Avatar from a URL
avatar_resp = requests.post(f"{BASE}/v3/avatars", headers=HEADERS, json={
"type": "photo",
"name": "Demo Avatar",
"file": {
"type": "url",
"url": "https://example.com/portrait.jpg"
}
})
avatar_id = avatar_resp.json()["data"]["avatar_item"]["id"]
print(f"Avatar created: {avatar_id}")
# 2. Generate a video
video_resp = requests.post(f"{BASE}/v3/videos", headers=HEADERS, json={
"avatar_id": avatar_id,
"script": "Welcome! This is a Photo Avatar created from a single image.",
"voice_id": "YOUR_VOICE_ID",
"resolution": "1080p",
"aspect_ratio": "16:9"
})
video_id = video_resp.json()["data"]["video_id"]
print(f"Video created: {video_id}")
# 3. Poll until done
while True:
status_resp = requests.get(f"{BASE}/v3/videos/{video_id}", headers=HEADERS)
data = status_resp.json()["data"]
print(f"Status: {data['status']}")
if data["status"] == "completed":
print(f"Download: {data['video_url']}")
break
elif data["status"] == "failed":
print(f"Error: {data.get('failure_message')}")
break
time.sleep(10)
Photo Avatar–specific parameters
These parameters are only available when using a Photo Avatar (avatar_type: photo_avatar):
| Parameter | Type | Description |
|---|
motion_prompt | string | Natural-language prompt to control body motion (e.g. “nodding gently”) |
expressiveness | string | high, medium, or low (default: low) |
Example with motion and expressiveness
{
"avatar_id": "YOUR_PHOTO_AVATAR_ID",
"script": "Let me show you our quarterly results.",
"voice_id": "YOUR_VOICE_ID",
"motion_prompt": "gesturing with hands while presenting",
"expressiveness": "high"
}
Optional parameters
| Parameter | Type | Description |
|---|
title | string | Display name in the HeyGen dashboard |
resolution | string | 1080p or 720p |
aspect_ratio | string | 16:9 or 9:16 |
remove_background | boolean | Remove the avatar background |
background | object | Set a solid color (type: "color") or image background |
voice_settings | object | Adjust speed, pitch, and locale |
callback_url | string | Webhook URL for completion notification |
Photo quality matters. Use a well-lit, front-facing portrait with a neutral expression for the best results. Avoid sunglasses, hats covering the forehead, or extreme angles.
Using a preset Photo Avatar
You can skip avatar creation and use a public preset avatar instead:
curl -X GET "https://api.heygen.com/v3/avatars/looks?avatar_type=photo_avatar&ownership=public" \
-H "x-api-key: YOUR_API_KEY"
Pick any id from the response and use it directly as your avatar_id in POST /v3/videos.