Create AI videos from the terminal. Official CLI for the HeyGen video generation API.
HeyGen CLI
Make AI videos from the command line. Drive HeyGen with code, not clicks.

Full reference and examples: developers.heygen.com/cli.
Built for
- Coding agents β Claude Code, Codex, and others
- CI/CD pipelines β weekly recap videos, release-note vlogs
- Bulk operations β translate 100 videos in one shell loop
- Custom integrations β wrap it in your own tool
Agent skills
heygen-com/skills β one-line install for Claude Code, Codex, and other agents. Create your own avatar and generate a video in a single conversation.
Agent-first by design
- JSON on stdout, structured errors on stderr, stable exit codes.
- Self-describing.
--request-schemaand--response-schemareturn JSON Schema without auth or API calls. - Non-interactive by default. Set
HEYGENAPIKEYand nothing reads a TTY. - Tell us how it went. After a flow works (or when you hit a bug), run
heygen feedback --rating <1-5> --comment "...". It sends an anonymous rating + note (no API key needed); honors the analytics opt-out. Agents should use this for bugs rather than opening GitHub issues automatically (see Reporting bugs).
Install
curl -fsSL https://static.heygen.ai/cli/install.sh | bash
Single static binary, no runtime required. Installs to ~/.local/bin.
Supported platforms: macOS, Linux, and Windows (via WSL).
You only need a HeyGen API key β see Authenticate below.
Updates
heygen update # install the latest version
Shell completion
Tab-completion for commands, subcommands, and flags is available for bash, zsh, fish, and PowerShell:
source <(heygen completion zsh) # current shell (bash/zsh/fish)
heygen completion zsh > "${fpath[1]}/_heygen" # persist (zsh; adjust path per shell)
Run heygen completion --help for per-shell install instructions.
Authenticate
Choose one of the options below. The first three are agent- and CI-friendly; the last two are for humans.
1. Environment variable β agents, CI; ephemeral, no file on disk:
export HEYGENAPIKEY=your-key-here
2. Pipe to auth login β agents; persists API key to ~/.heygen/credentials:
echo "$KEY" | heygen auth login
3. Explicit --api-key β humans paste from a prompt:
heygen auth login --api-key
4. Browser OAuth β humans, Pro / Max subscription users; persists OAuth tokens to ~/.heygen/credentials:
heygen auth login --oauth
5. Interactive picker β humans, no flag: a TTY prompt lets you choose between API key (uses API credits) and OAuth (uses subscription credits):
heygen auth login
Verify any of the above with heygen auth status. Get an API key at app.heygen.com/settings/api.
Single-credential file. The credentials file holds at most one of>api_key/ OAuth tokens at any time. Runningheygen auth login(any method) clears the other on success β re-login overwrites, it does not merge.heygen auth statuswill tell you which one is active.
HEYGENAPIKEY in the environment always wins over either file credential.
Quick start
1. Create a finished video from a prompt (returns JSON including video_id):
heygen video-agent create --prompt "30-second product demo" --wait
2. Get its metadata and share link:
heygen video get <video-id>
Returns JSON with videourl (raw mp4), videopageurl (shareable UI link), thumbnailurl, and duration. Pipe to jq to extract what you need:
heygen video get <video-id> | jq -r '.data.videopageurl'
β https://app.heygen.com/videos/...
3. Download the mp4:
heygen video download <video-id>
Add --human to any command for a readable layout. Set HEYGEN_OUTPUT=human to make it the default.
In --human mode, list responses render as a table and single-object responses render as an indented, humanized layout (similar to kubectl describe). Keys are humanized per segment (autoreload β Auto Reload), with common acronyms uppercased (videourl β Video URL); nested objects indent under a Label: header, scalar siblings align locally within each block, arrays of scalars join inline (a, b, c), and arrays of objects render as YAML-style - sequence items. Empty objects, empty arrays, and nulls show as (none). Long scalar values (e.g. pre-signed download URLs) are printed in full and may wrap in a narrow terminal; pipe the default JSON to jq if you need to extract one cleanly. For example:
Status: completed
Wallet:
Auto Reload:
Enabled: false
Currency: usd
Remaining Balance: 476.78
Tags: alpha, beta
--human is a readable layout for terminals and may change between releases; scripts and agents should consume the default JSON output, which is stable. JSON output (the default) is never altered.
Commands
Mirrors the HeyGen v3 API. Pattern: heygen <noun> <verb>.
| Group | What it does | |-------|-------------| | video-agent | Create videos from text prompts using AI | | video | Create, list, get, delete, download videos | | avatar | List and manage avatars and looks | | voice | List voices, design voices, generate speech | | audio | Search the background-music catalog | | video-translate | Translate videos into other languages | | lipsync | Dub or replace audio on existing videos | | webhook | Manage webhook endpoints and events | | asset | Upload files for use in video creation | | user | Account info and billing |
Every command supports --help.
How it behaves
| Aspect | Behavior | |--------|----------| | stdout | Always JSON. Even video download β binary writes to disk; stdout emits {"asset", "message", "path"} so you can chain on .path. | | stderr | Structured envelope on error: {"error": {"code", "message", "hint", "param", "docurl", "requestid"}}. code/message are always present; hint/param/docurl/requestid appear when applicable (param/docurl are surfaced from the API for validation and documented errors). Stable code values for programmatic branching. A code prefixed cli is originated by the CLI itself (client/transport/local conditions, e.g. clidownloadurlexpired). A bare code is either an API code (or a CLI mirror of one) or one of a small frozen set of legacy CLI codes that predate the prefix. The cli prefix is reserved for the CLI, so a new CLI code can never collide with an API code. | | Exit codes | 0 ok Β· 1 API or network Β· 2 usage Β· 3 auth / not permitted Β· 4 timeout under --wait (stdout contains partial resource for resume) | | Request bodies | Flags for simple inputs; -d for nested JSON (inline, file path, or - for stdin). Flags override matching fields. | | Async jobs | --wait blocks with exponential backoff; --timeout sets max (default 20m). 429s and 5xx retry automatically. |
Example error envelope:
{"error": {"code": "notfound", "message": "Video not found", "hint": "Check ID with: heygen video list", "docurl": "https://developers.heygen.com/docs/error-codes#not-found"}}
Configuration
| File | Purpose | |------|---------| | ~/.heygen/credentials | API key or OAuth tokens (one at a time β see Authenticate) | | ~/.heygen/config.toml | Output format and other non-secret settings |
HEYGENAPIKEY and HEYGEN_OUTPUT env vars override the respective files.
heygen config list # show all settings with sources
Reporting bugs
- Quick signal (recommended for agents):
heygen feedback --rating <1-5> --comment "...". Goes to private, anonymous analytics. Safe to run unattended. - Tracked bug a maintainer should see: open a GitHub issue. This repo is public, so review what you paste first and omit anything sensitive (API keys, prompts, internal URLs, personal data).
heygen feedback for bug signal; if something seems worth tracking, surface it to the user and let a human file the issue after reviewing it for sensitive content.
Contributing
See CONTRIBUTING.md.