Skip to main content
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

1

Create a session

POST /v3/video-agents/sessions — Send your initial prompt. The agent begins processing.
2

Poll for status

GET /v3/video-agents/sessions/{session_id} — Check progress and read agent messages. The session pauses at reviewing status.
3

Review and iterate

POST /v3/video-agents/sessions/{session_id}/messages — Send feedback or approve the storyboard. Repeat as needed.
4

Generate the video

Send a message with auto_proceed: true or approve the storyboard. The session moves to generating, then completed.

Session statuses

StatusDescription
processingAgent is working (scripting, composing scenes, preparing storyboard).
reviewingAgent is paused, waiting for your input. Review the storyboard and messages.
generatingStoryboard approved — video is rendering.
completedVideo is ready. Retrieve it via GET /v3/videos/{video_id}.
failedSomething went wrong. Check messages for error details.

Create a session

POST https://api.heygen.com/v3/video-agents/sessions

Request body

ParameterTypeRequiredDescription
promptstringYesInitial message to the agent (1–10,000 characters).
avatar_idstringNoSpecific avatar look ID.
voice_idstringNoSpecific voice ID for narration.
orientationstringNo"landscape" or "portrait". Auto-detected if omitted.
filesarrayNoUp to 20 file attachments (asset_id, url, or base64). See Upload Assets.
auto_proceedbooleanNoIf true, skip interactive review and go straight to video generation. Default: false.
callback_urlstringNoWebhook URL for future notifications (reserved for future use).
callback_idstringNoCaller-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

FieldTypeDescription
session_idstringSession identifier.
statusstringCurrent status: processing, reviewing, generating, completed, failed.
progressintegerProgress percentage (0–100).
titlestring | nullAgent-generated session title.
video_idstring | nullVideo ID once generation starts. Use with GET /v3/videos/{video_id}.
created_atintegerUnix timestamp of session creation.
messagesarrayMost recent visible messages (max 40, newest-first).

Message object

FieldTypeDescription
rolestring"user" or "model".
contentstringMessage text.
typestring"text", "resource", or "error".
created_atinteger | nullUnix timestamp.
resource_idsarray | nullResource 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

ParameterTypeRequiredDescription
messagestringYesYour message to the agent (1–10,000 characters).
avatar_idstringNoOverride avatar for this message.
voice_idstringNoOverride voice for this message.
filesarrayNoAdditional file attachments (max 20).
auto_proceedbooleanNoIf 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

ParameterTypeDefaultDescription
resource_idsstringComma-separated resource IDs to fetch specific resources.
typestringFilter by type: image, video, draft, avatar, voice, etc.
sourcestringFilter by source: generated or user_uploaded.
limitinteger8Resources per page (1–100).
tokenstringOpaque 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

FieldTypeDescription
resource_idstringUnique identifier. Referenced in message resource_ids.
resource_typestringType: image, video, draft, avatar, voice, etc.
source_typestring | null"generated" or "user_uploaded".
urlstring | nullPrimary media URL.
thumbnail_urlstring | nullThumbnail URL.
preview_urlstring | nullPreview URL.
created_atinteger | nullUnix timestamp.
metadataobject | nullType-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 '{}'
Response
{
  "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)