Prerequisites
A Digital Twin
avatar_id (type: digital_twin). Use GET /v3/avatars/looks?avatar_type=digital_twin to find yours.A
voice_id for the voice you want. Use GET /v3/voices to browse available voices.Step 1 — Find your Digital Twin
List your private Digital Twin looks to get theavatar_id:
id field of the look you want. This is your avatar_id.
Step 2 — Choose a rendering engine
HeyGen v3 supports three rendering engines for Digital Twins. You select the engine via theengine object in your video creation request.
Before requesting an engine, check the
supported_api_engines array on the avatar look via GET /v3/avatars/looks/{look_id} — it lists which of avatar_iii, avatar_iv, and avatar_v the look accepts, and requesting an engine that isn’t listed will be rejected. See Models for full details on each engine.Step 3 — Create the video
Send aPOST request to /v3/videos with type: "avatar", your Digital Twin ID, a script, and a voice.
Using Avatar IV (default)
Omit theengine field or pass {"type": "avatar_iv"} — Avatar IV is the default:
Using Avatar V (higher quality)
Pass{"type": "avatar_v"} in the engine field to request cross-reference-driven animation:
motion_prompt is supported on both Avatar IV and Avatar V — pass a natural-language prompt to control body motion and hand gestures.expressiveness remains an Avatar IV-only parameter. Do not include it when using Avatar V — it will cause a validation error.Step 4 — Poll for completion
Video generation is asynchronous. PollGET /v3/videos/{video_id} until status is completed:
Status values
Once completed, the response includes everything you need to download and display the result:
These are presigned URLs with a limited expiry window — download promptly, or call
GET /v3/videos/{video_id} again to get fresh URLs. When status is failed, the response includes a machine-readable failure_code alongside the human-readable failure_message.
Full example
Optional parameters
Captions and subtitles
Captions are off by default — omitcaption and video_url is a clean render with no subtitles. To generate captions, pass a caption object:
subtitle_url in the status response, while the video itself stays clean — you control how subtitles display in your own player. To additionally burn captions into the rendered video, set a style:
caption is an object on /v3/videos. Boolean-style fields like caption: true or enable_caption (used by the v2 API and by the template endpoint) fail /v3/videos validation with invalid_parameter (“Extra inputs are not permitted”). Use the object form above.captioned_video_url (or the url from a webhook payload that points at the captioned render). Fetch GET /v3/videos/{video_id} and download video_url for the caption-free file.
Using webhooks instead of polling
Instead of polling, pass acallback_url when creating the video. HeyGen will send a POST request to that URL when the video completes or fails.
Register a webhook endpoint via
POST /v3/webhooks/endpoints and subscribe to avatar_video.success and avatar_video.fail events for production use.
