Agent skill

HeyGen Webhooks Skill

Receive and verify HeyGen webhooks. Use when setting up HeyGen webhook endpoints, debugging the `signature` header HMAC-SHA256 verification, or handling AI video events like avatar_video.success, avatar_video.fail, video_translate.success, or video_translate.fail.

Install this skill

npx skills add hookdeck/webhook-skills --skill heygen-webhooks


When to Use This Skill

  • How do I receive HeyGen webhooks?
  • How do I verify the HeyGen webhook signature header?
  • How do I know when a HeyGen avatar video has finished rendering (avatar_video.success)?
  • How do I handle video_translate.success or video_translate.fail events?
  • Why is my HeyGen webhook signature verification failing?

Verification (core)

HeyGen sends the signature in a header literally named signature: the hex-encoded HMAC-SHA256 of the raw request body, with no timestamp and no prefix. The key is the endpoint secret returned when you create the endpoint (it looks like whsec_k7x9m2...), used whole, as a UTF-8 string.

This is NOT Standard Webhooks. Do not use the standardwebhooks or svix libraries, and do not strip the whsec_ prefix or base64-decode the secret. There are no webhook-id / webhook-timestamp / webhook-signature headers.

const crypto = require('crypto');

function verifyHeyGenSignature(rawBody, signature, secret) {
  if (!signature || !secret) return false;
  const expected = crypto
    .createHmac('sha256', secret)      // secret as-is, including "whsec_"
    .update(rawBody)                   // raw Buffer, not parsed JSON
    .digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(signature.trim().toLowerCase());
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

HeyGen has no webhook-verification SDK, so all three examples verify manually. Read the raw body first (in Express, express.raw({ type: '*/*' }) so any content type verifies).

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Common Event Types

The event type is in the payload's event_type field and the data is in event_data.

EventTriggered When
avatar_video.successAn avatar video finished rendering (event_data.video_id, url, callback_id, ...)
avatar_video.failAvatar video generation failed
video_translate.successA video translation completed
video_translate.failA video translation failed
video_agent.success / video_agent.failA Video Agent session completed / failed

For the full event list (GIF, caption, avatar training, proofread, live avatar, ...), see references/overview.md and HeyGen's webhook events docs.

Environment Variables

# Signing secret returned once by POST /v3/webhooks/endpoints (or rotate-secret)
HEYGEN_WEBHOOK_SECRET=whsec_your_endpoint_secret

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 heygen --path /webhooks/heygen

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 4, 2026

View on GitHub →