Skip to main content
Instead of polling GET /v3/videos/{video_id} for status, you can register a webhook endpoint to receive a POST notification when a video completes, fails, or other events occur. See Webhook Events for the full event catalog and payload shapes. Authentication is the same X-Api-Key header as the rest of the v3 API; see the API Key guide.

Create an Endpoint

Register a URL to receive webhook events with POST /v3/webhooks/endpoints. The response includes an endpoint_id and a secret for verifying payloads: store it securely, as it will not be shown again.
url must be a publicly accessible HTTPS URL. Omit events or set it to null to receive all events; see Webhook Events and GET /v3/webhooks/event-types for the full list. entity_id scopes the endpoint to a specific resource (e.g. a personalized video project).

Manage Endpoints

Rotate Signing Secret

POST /v3/webhooks/endpoints/{endpoint_id}/rotate-secret returns a new secret. The old secret is invalidated immediately on rotation; deploy the new secret to your verifier promptly. Expect a brief window of failed verifications during rollover, and handle this gracefully on the receiver.

Verifying Payloads

Every webhook delivery includes a signature header derived from your endpoint secret. Always verify before trusting the payload — without verification, anyone who learns your URL can forge events. HeyGen signs the raw request body with HMAC-SHA256 using the endpoint secret returned by Create Endpoint or Rotate Secret. Compute the same digest on your side and compare in constant time.
Verify against the raw body bytes, not a re-serialized JSON object. Any whitespace or key-order change will break the HMAC. In Express, use express.raw(); in Flask, use request.get_data() before request.get_json().

Delivery, retries, and idempotency

  • Success criteria: respond with 2xx within 10 seconds. Slow handlers will be timed out and retried.
  • Retries: failed deliveries are retried with exponential backoff for up to 24 hours.
  • Idempotency: a single event can be delivered more than once (a retry after a transient failure). A retry resends the same payload, so de-duplicate on a stable field in the body. For avatar video events, use event_data.video_id together with event_type, or the callback_id you set when creating the video.
For the full list of event types and payload shapes, see Webhook Events.

Using Callbacks Instead

If you don’t need a persistent webhook endpoint, pass a callback_url directly when creating a video, for example via Create Video Agent Session or Create Video Translation. This sends a one-off notification for that specific request without registering an endpoint:
The callback_id is echoed back in the webhook payload so you can correlate the notification with your request.