Interactive sessions give you a multi-turn conversation with the Video Agent. Instead of going straight to rendering, the agent pauses at checkpoints (like storyboard review) so you can provide feedback, adjust direction, and approve before the final video is generated.
Session lifecycle
Create a session
POST /v3/video-agents/sessions — Send your initial prompt. The agent begins processing.
Poll for status
GET /v3/video-agents/sessions/{session_id} — Check progress and read agent messages. The session pauses at reviewing status.
Review and iterate
POST /v3/video-agents/sessions/{session_id}/messages — Send feedback or approve the storyboard. Repeat as needed.
Generate the video
Send a message with auto_proceed: true or approve the storyboard. The session moves to generating, then completed.
Session statuses
| Status | Description |
|---|
processing | Agent is working (scripting, composing scenes, preparing storyboard). |
reviewing | Agent is paused, waiting for your input. Review the storyboard and messages. |
generating | Storyboard approved — video is rendering. |
completed | Video is ready. Retrieve it via GET /v3/videos/{video_id}. |
failed | Something went wrong. Check messages for error details. |
Create a session
POST https://api.heygen.com/v3/video-agents/sessions
Request body
| Parameter | Type | Required | Description |
|---|
prompt | string | Yes | Initial message to the agent (1–10,000 characters). |
avatar_id | string | No | Specific avatar look ID. |
voice_id | string | No | Specific voice ID for narration. |
orientation | string | No | "landscape" or "portrait". Auto-detected if omitted. |
files | array | No | Up to 20 file attachments (asset_id, url, or base64). See Upload Assets. |
auto_proceed | boolean | No | If true, skip interactive review and go straight to video generation. Default: false. |
callback_url | string | No | Webhook URL for future notifications (reserved for future use). |
callback_id | string | No | Caller-defined ID persisted alongside callback_url. |
Set auto_proceed: true to skip the review step entirely — the session behaves like the one-shot /v3/video-agents endpoint but with a session you can track.
Example
curl -X POST "https://api.heygen.com/v3/video-agents/sessions" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Create a 2-minute onboarding video for new engineering hires. Cover team culture, dev tools, and first-week checklist.",
"orientation": "landscape"
}'
Response
{
"data": {
"session_id": "sess_abc123",
"created_at": 1711382400
}
}
Poll session status
GET https://api.heygen.com/v3/video-agents/sessions/{session_id}
Returns the current session status, progress percentage, chat messages, and the video_id once generation starts.
Response
{
"data": {
"session_id": "sess_abc123",
"status": "reviewing",
"progress": 45,
"title": "Engineering Onboarding Video",
"video_id": null,
"created_at": 1711382400,
"messages": [
{
"role": "model",
"content": "I've drafted a storyboard with 4 scenes covering team culture, dev environment setup, key tools, and the first-week checklist. Would you like to review it or should I proceed?",
"type": "text",
"created_at": 1711382450,
"resource_ids": ["res_storyboard_001"]
},
{
"role": "user",
"content": "Create a 2-minute onboarding video for new engineering hires.",
"type": "text",
"created_at": 1711382400,
"resource_ids": null
}
]
}
}
Response fields
| Field | Type | Description |
|---|
session_id | string | Session identifier. |
status | string | Current status: processing, reviewing, generating, completed, failed. |
progress | integer | Progress percentage (0–100). |
title | string | null | Agent-generated session title. |
video_id | string | null | Video ID once generation starts. Use with GET /v3/videos/{video_id}. |
created_at | integer | Unix timestamp of session creation. |
messages | array | Most recent visible messages (max 40, newest-first). |
Message object
| Field | Type | Description |
|---|
role | string | "user" or "model". |
content | string | Message text. |
type | string | "text", "resource", or "error". |
created_at | integer | null | Unix timestamp. |
resource_ids | array | null | Resource IDs resolvable via GET .../resources. |
Send a follow-up message
POST https://api.heygen.com/v3/video-agents/sessions/{session_id}/messages
Send feedback, request changes, or approve the storyboard. The agent processes your message and updates the session.
Request body
| Parameter | Type | Required | Description |
|---|
message | string | Yes | Your message to the agent (1–10,000 characters). |
avatar_id | string | No | Override avatar for this message. |
voice_id | string | No | Override voice for this message. |
files | array | No | Additional file attachments (max 20). |
auto_proceed | boolean | No | If true, skip remaining review steps and generate the video immediately. Default: false. |
Example: Request changes
curl -X POST "https://api.heygen.com/v3/video-agents/sessions/sess_abc123/messages" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Looks great, but add a scene about our code review process before the checklist scene."
}'
Example: Approve and generate
curl -X POST "https://api.heygen.com/v3/video-agents/sessions/sess_abc123/messages" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Looks perfect, go ahead and generate the video.",
"auto_proceed": true
}'
Response
{
"data": {
"session_id": "sess_abc123",
"run_id": "run_def456",
"title": "Engineering Onboarding Video"
}
}
After sending a message, poll GET /v3/video-agents/sessions/{session_id} to see the agent’s response and updated status.
Get session resources
GET https://api.heygen.com/v3/video-agents/sessions/{session_id}/resources
Retrieve generated assets associated with the session — storyboard images, draft videos, selected avatars, and voices.
Query parameters
| Parameter | Type | Default | Description |
|---|
resource_ids | string | — | Comma-separated resource IDs to fetch specific resources. |
type | string | — | Filter by type: image, video, draft, avatar, voice, etc. |
source | string | — | Filter by source: generated or user_uploaded. |
limit | integer | 8 | Resources per page (1–100). |
token | string | — | Opaque pagination token. |
Example
curl "https://api.heygen.com/v3/video-agents/sessions/sess_abc123/resources?type=image" \
-H "X-Api-Key: $HEYGEN_API_KEY"
Response
{
"data": {
"resources": [
{
"resource_id": "res_storyboard_001",
"resource_type": "image",
"source_type": "generated",
"url": "https://files.heygen.com/resources/res_storyboard_001.png",
"thumbnail_url": "https://files.heygen.com/resources/res_storyboard_001_thumb.png",
"created_at": 1711382450,
"metadata": {}
}
],
"next_cursor": null
}
}
Resource object
| Field | Type | Description |
|---|
resource_id | string | Unique identifier. Referenced in message resource_ids. |
resource_type | string | Type: image, video, draft, avatar, voice, etc. |
source_type | string | null | "generated" or "user_uploaded". |
url | string | null | Primary media URL. |
thumbnail_url | string | null | Thumbnail URL. |
preview_url | string | null | Preview URL. |
created_at | integer | null | Unix timestamp. |
metadata | object | null | Type-specific metadata. |
Stop a session
POST https://api.heygen.com/v3/video-agents/sessions/{session_id}/stop
Stop an in-progress agent run. The agent halts at the next checkpoint, and partial results are preserved.
curl -X POST "https://api.heygen.com/v3/video-agents/sessions/sess_abc123/stop" \
-H "X-Api-Key: $HEYGEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
{
"data": {
"session_id": "sess_abc123"
}
}
Full workflow example
import time
import requests
API_KEY = "your-api-key"
HEADERS = {"X-Api-Key": API_KEY}
BASE = "https://api.heygen.com/v3"
# 1. Create session
session = requests.post(
f"{BASE}/video-agents/sessions",
headers=HEADERS,
json={"prompt": "Create a 90-second product demo for our analytics dashboard"},
).json()["data"]
session_id = session["session_id"]
print(f"Session created: {session_id}")
# 2. Poll until reviewing
while True:
status_resp = requests.get(
f"{BASE}/video-agents/sessions/{session_id}",
headers=HEADERS,
).json()["data"]
print(f"Status: {status_resp['status']} ({status_resp.get('progress', 0)}%)")
if status_resp["status"] == "reviewing":
# Print agent's message
for msg in reversed(status_resp.get("messages", [])):
if msg["role"] == "model":
print(f"Agent: {msg['content']}")
break
break
elif status_resp["status"] in ("completed", "failed"):
break
time.sleep(5)
# 3. Approve and generate
requests.post(
f"{BASE}/video-agents/sessions/{session_id}/messages",
headers=HEADERS,
json={"message": "Looks great, generate it!", "auto_proceed": True},
)
# 4. Poll until video is ready
while True:
status_resp = requests.get(
f"{BASE}/video-agents/sessions/{session_id}",
headers=HEADERS,
).json()["data"]
if status_resp["status"] == "completed" and status_resp.get("video_id"):
video = requests.get(
f"{BASE}/videos/{status_resp['video_id']}",
headers=HEADERS,
).json()["data"]
if video["status"] == "completed":
print(f"Video ready: {video['video_url']}")
break
elif status_resp["status"] == "failed":
print("Session failed")
break
time.sleep(10)