Draft: these docs describe OctaVideo as it will be at launch; some features may not be live yet.
OctaVideoDocs

Webhooks

Let OctaVideo call your server when a video is ready, fails, or gets its transcript.

Webhooks tell your server about events the moment they happen, so you never poll. OctaVideo sends an HTTPS POST with a JSON body to the URL you choose, signed with a secret only you and OctaVideo know.

Add an endpoint

Open API & embeds → Webhooks in the library, and select Add endpoint.

Enter your endpoint's URL. It must use https:// and answer within 10 seconds.

Pick the events to receive, then save. Copy the Signing secret (it starts with whsec_) into your server's environment, for example OCTAVIDEO_WEBHOOK_SECRET.

Each library has its own endpoints and secrets. Use Send test event to check your endpoint before going live.

Events

EventWhen it's sentdata
video.readyProcessing finished and the video can be played.video
video.failedProcessing or an import failed for good. failure_reason says why.video
transcript.readyA transcription finished.video, language
transcript.failedA transcription failed.video, reason

The request

POST https://your-server.example/webhooks/octavideo
Content-Type: application/json
OctaVideo-Event: video.ready
OctaVideo-Delivery: 2b7e4f1a-9c3d-4e8a-b5f6-0a1b2c3d4e5f
OctaVideo-Signature: t=1761384900,v1=5f2b9c0e7a4d…

{
  "id": "2b7e4f1a-9c3d-4e8a-b5f6-0a1b2c3d4e5f",
  "type": "video.ready",
  "created_at": "2026-10-25T09:35:00Z",
  "library_id": "0b8e5d3a-1c2f-4e6a-8b7d-9f0a1b2c3d4e",
  "data": {
    "video": {
      "id": "6f1c2b9e-4a7d-4f3e-9b8a-2d5c7e1f0a34",
      "title": "Lesson 1: Introduction",
      "encoding_status": "ready",
      "progress": 100,
      "duration_seconds": 754.2
    }
  }
}

data.video has the same fields as Get a video.

Verify the signature

Always check OctaVideo-Signature before you trust a request:

  1. Split the header into t (a Unix timestamp) and v1 (the signature).
  2. Compute HMAC-SHA256 of t + "." + raw request body with your signing secret, as hex.
  3. Compare it with v1 in constant time, and reject requests where t is more than 5 minutes old.

Use the raw body bytes: parsing and re-serializing the JSON changes them and breaks the signature.

import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post('/webhooks/octavideo', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('OctaVideo-Signature') ?? '';
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const expected = crypto
    .createHmac('sha256', process.env.OCTAVIDEO_WEBHOOK_SECRET)
    .update(`${parts.t}.${req.body}`)
    .digest('hex');

  const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
  const valid =
    parts.v1?.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
  if (!fresh || !valid) return res.sendStatus(400);

  const event = JSON.parse(req.body);
  // Queue the work, then answer quickly.
  res.sendStatus(204);
});

The SDKs include a helper that does these checks for you.

Retries and duplicates

  • Answer with any 2xx status within 10 seconds. Do slow work after answering, for example in a queue.
  • Any other answer, or no answer, is retried with a growing delay for up to 24 hours.
  • The same event can arrive more than once, and events can arrive out of order. Use id to skip events you've already handled, and get the video when you need its latest state.
  • Webhooks in the console lists each delivery with its status and response, and can resend one.

Keep the secret secret

Anyone with the signing secret can forge events. If it leaks, select Roll secret on the endpoint and update your server.

On this page