# api.video Webhooks

## When to Use This Skill

* How do I receive api.video webhooks?
* How do I verify the `X-Api-Video-Signature` header?
* Why is my api.video webhook signature verification failing?
* Handling `video.encoding.quality.completed` or `video.source.recorded` events
* Reacting to `live-stream.broadcast.started` / `live-stream.broadcast.ended`

## Verification (core)

api.video signs the **exact raw request body** with HMAC-SHA256, keyed with the webhook's `signatureSecret` (`sig_sec_...`, used as UTF-8 bytes), and sends the **bare lowercase hex digest** in `X-Api-Video-Signature` (no prefix). Nothing else is signed: no timestamp, no id, so there is no replay window to check. This is a custom scheme, not Standard Webhooks, and there is no SDK helper, so verify manually.

```javascript
const crypto = require('crypto');

function verifyApiVideoSignature(rawBody, signatureHeader, secret) {
  // rawBody: Buffer of the unparsed request body
  if (!signatureHeader || !/^[0-9a-fA-F]{64}$/.test(signatureHeader)) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader.toLowerCase(), 'utf8'),
    Buffer.from(expected, 'utf8')
  );
}

```

```python
import hashlib, hmac, re

def verify_api_video_signature(raw_body: bytes, signature_header: str | None, secret: str) -> bool:
    if not signature_header or not re.fullmatch(r"[0-9a-fA-F]{64}", signature_header):
        return False
    expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(signature_header.lower().encode(), expected.encode())

```

Return `401` for a missing, malformed or non-matching signature. Verify the raw bytes **before** parsing (in Express use `express.raw({ type: '*/*' })`; in Next.js `await request.arrayBuffer()`; in FastAPI `await request.body()`).

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/api-video-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/api-video-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/api-video-webhooks/examples/fastapi/).

## Event Types

The event name is the body's top-level `type` field. The body is flat: `type`, `emittedAt`, plus the event's ids and fields. (`X-Api-Video-WebhookID` identifies the subscription, not the event.)

| Event | Triggered When |
| --- | --- |
| `video.source.recorded` | A video's source file has been received/recorded |
| `video.encoding.quality.completed` | One rendition (`encoding`, `quality`, e.g. `hls` / `720p`) finished encoding |
| `video.caption.generated` | A caption was generated for a video |
| `video.summary.generated` | A summary was generated for a video |
| `live-stream.broadcast.started` | A live stream broadcast started |
| `live-stream.broadcast.ended` | A live stream broadcast ended |

> **For the full event reference**, see [api.video webhooks](https://docs.api.video/reference/create-and-manage-webhooks).

## Important Headers

| Header | Description |
| --- | --- |
| `X-Api-Video-Signature` | Hex HMAC-SHA256 of the raw body (verify this) |
| `X-Api-Video-WebhookID` | ID of the webhook subscription that fired |

## Environment Variables

```bash
# signatureSecret returned by POST /webhooks (201) or GET /webhooks/{webhookId}
API_VIDEO_WEBHOOK_SECRET=sig_sec_your_signature_secret

```

## Delivery

A `1xx`/`2xx` response is success. Any status above `299` is retried 3 times at 3-second intervals, so respond quickly and process idempotently.

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 api-video --path /webhooks/api-video

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/api-video-webhooks/references/overview.md) - What api.video webhooks are, events, payloads
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/api-video-webhooks/references/setup.md) - Create a webhook and get the signature secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/api-video-webhooks/references/verification.md) - Signature verification details, test vector and gotchas