Skip to main content
Upload images, videos, audio, or PDFs to get an asset_id you can reference in other endpoints — like POST /v3/video-agents, POST /v3/videos, or POST /v3/avatars.

Upload an Asset

curl -X POST https://api.heygen.com/v3/assets \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@./my-photo.png"
Response
{
  "data": {
    "asset_id": "ast_abc123",
    "url": "https://files.heygen.com/asset/ast_abc123.png",
    "mime_type": "image/png",
    "size_bytes": 204800
  }
}

Supported File Types

CategoryFormats
ImagePNG, JPEG
VideoMP4, WebM
AudioMP3, WAV
DocumentPDF
Max file size: 32 MB. MIME type is auto-detected from file bytes. For larger files, use the direct upload flow below.

Direct Upload for Large Files

POST /v3/assets proxies file bytes through the API, which is why it’s capped at 32 MB. For larger files, use the presigned direct upload flow — three required steps:
  1. POST /v3/assets/direct-uploads with filename, content_type, and exact size_bytes → returns asset_id, a presigned upload_url, and upload_headers.
  2. PUT the raw file bytes to upload_url, sending upload_headers verbatim, before the URL expires (expires_in_seconds).
  3. POST /v3/assets/{asset_id}/complete to finalize. Idempotent. The asset_id is not usable until this step succeeds.
# 1. Initialize
curl -X POST https://api.heygen.com/v3/assets/direct-uploads \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"filename": "footage.mp4", "content_type": "video/mp4", "size_bytes": 134217728}'

# 2. PUT the file bytes to the returned upload_url (with upload_headers)
curl -X PUT "UPLOAD_URL" -H "Content-Type: video/mp4" --upload-file ./footage.mp4

# 3. Complete
curl -X POST https://api.heygen.com/v3/assets/ASSET_ID/complete \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
The per-upload cap for this flow is returned as max_bytes in the initialize response. See Upload Assets for full examples in Python and Node.js.

Using Assets

Once uploaded, reference the asset_id anywhere the API accepts asset inputs:
// In POST /v3/video-agents (file attachments)
{
  "prompt": "Explain this diagram",
  "files": [{ "type": "asset_id", "asset_id": "ast_abc123" }]
}
// In POST /v3/avatars (photo avatar)
{
  "type": "photo",
  "name": "My Avatar",
  "file": { "type": "asset_id", "asset_id": "ast_abc123" }
}
Anywhere that accepts an asset also accepts a direct URL ({"type": "url", "url": "https://..."}) or base64 ({"type": "base64", "media_type": "image/png", "data": "..."}). The 32 MB per-file limit applies to URL inputs too — for larger files, upload via the direct upload flow and pass the asset_id. Use asset_id when you need to reuse the same file across multiple requests.