HeyGen API avatar ID and voice ID: where to find them
In HeyGen's v3 API, avatar_id is a look id from GET /v3/avatars/looks, and voice_id comes from GET /v3/voices or the look's default voice.
In HeyGen's v3 API, the avatar_id you send is the id of an avatar look. List looks with GET /v3/avatars/looks and copy a look's id into POST /v3/videos or POST /v3/video-agents. For the voice, each look carries a default_voice_id, and GET /v3/voices lists the rest by voice_id.
Every HeyGen fact here is quoted from HeyGen's own developer pages, read on 2026-09-29: Avatar Looks, Browse Voices, Error Codes and the Endpoint Version Comparison. The short Sume section at the end comes from Create new avatar.
How do I get a HeyGen avatar ID from the API?
HeyGen calls one outfit, pose or style of a character a look, and says the look is "the value you pass as avatar_id to video creation". The list call is paged: 20 looks by default, up to 50 with limit, and when has_more is true you pass next_token back as token.
ownership=publicreturns HeyGen's presets,ownership=privateyour own avatars; omit it for both.avatar_typefilters tostudio_avatar,digital_twinorphoto_avatar.group_idreturns every look of one character.- Check
supported_api_enginesbefore you request anengine: an engine the look doesn't list returnsinvalid_parameter. Omittingengineuses Avatar IV. - For private avatars,
statusshows training:processing,completedorfailed.
curl "https://api.heygen.com/v3/avatars/looks?ownership=private&limit=5" \
-H "X-Api-Key: $HEYGEN_API_KEY"Where do I find a HeyGen voice ID?
Two places. Each look in the list above has a default_voice_id. For any other voice, call GET /v3/voices, filter by language or gender, and use the voice_id it returns in POST /v3/videos, POST /v3/video-agents or POST /v3/voices/speech.
One default trips people up: type defaults to "public", the shared library. Your cloned voices only appear with type=private. You can also leave voice_id out of a v3 avatar video: HeyGen's create reference says the avatar's default voice is used as the fallback when avatar_id is set.
Why does my old avatar ID or endpoint not work?
Older tutorials use v1 and v2 routes such as GET /v1/avatar.list and GET /v2/avatars. HeyGen maps these to GET /v3/avatars, which lists avatar groups (characters), and voice listing to GET /v3/voices. The id a v3 video takes is still a look id from GET /v3/avatars/looks. It says v1/v2 endpoints stay operational until October 31, 2026 and will be retired from November 1, 2026. The HeyGen v2 to v3 migration post covers the switch.
What does avatar_not_found mean?
It's a 404: HeyGen found no avatar with that id. The page asks you to verify the id, that a new avatar has finished training, and that the avatar belongs to your account or is public. The table lists the other id errors worth knowing.
| Error code | HTTP status | What HeyGen says it means |
|---|---|---|
avatar_not_found | 404 | The avatar_id is wrong, the avatar hasn't finished training, or it isn't yours or public |
voice_not_found | 404 | The voice_id is wrong or not in your account; a cloned voice may still be processing |
avatar_not_usable | 400 | The avatar failed content moderation or its creation failed; pick another |
avatar_consent_required | 400 | The avatar group needs its consent flow completed first |
voice_not_usable | 403 | The voice is in a state that blocks generation; retrying won't fix it |
plan_upgrade_required | 402 | For example, a premium avatar that isn't on your plan |
How does Sume name avatars instead?
On Sume the avatar id is a name you pick: you choose an avatar_handle when you create the avatar; a leading @ is allowed and stored without it. A talking-video request then references a ready avatar by that same avatar_handle (Generate avatar video). GET /v1/avatar-1.0/avatars lists your avatars; it is in the Sume API reference.
For the API key setup on HeyGen's side, see how to get a HeyGen API key.
Sources
Related posts
More in Developers
- How does the Higgsfield API work? Requests, limits, billing
Higgsfield's API is asynchronous: submit to a model endpoint, keep the request_id, poll or take a webhook, download. Billing and limits explained.
- httpx retry: what HTTPTransport(retries=n) covers
httpx retries only ConnectError and ConnectTimeout, via HTTPTransport(retries=n). For read errors, 429 and 503, write a loop that keeps one Idempotency-Key.
- 409 idempotency_conflict vs idempotency_key_in_use: which one to retry
Both are 409s on a Sume Format run create. idempotency_key_in_use is a concurrent duplicate you resend; idempotency_conflict is a changed body you must fix.
- Idempotency key replay returns the original response: read the flag
Replaying an Idempotency-Key on a Sume run create returns the original receipt with idempotency_hit true. How to spot a replay, and what a new body does.
Written by Sume