← API docs

Webhooks

We deliver job results to your endpoint with an HMAC signature so you can verify origin.

Events

  • video.ready — generation succeeded; payload includes id, doSpacesUrl, previewUrl, aspectRatio.
  • video.failed — generation failed; payload includes id and error message. Tokens are auto-refunded.

Payload example — video.ready

POST https://your-app/webhooks/gvm
Headers:
  Content-Type: application/json
  X-GVM-Event: video.ready
  X-GVM-Delivery: 7c6e1f31-5d53-4f1e-89a4-6a2bdb1d0f47
  X-GVM-Signature: t=1714560000,v1=8b2…  (HMAC-SHA256, hex)

Body:
{
  "id": "vid_01HW…",
  "status": "READY",
  "prompt": "A golden-hour drone shot…",
  "doSpacesUrl": "https://nyc3.cdn.digitaloceanspaces.com/…/video.mp4",
  "previewUrl": "https://nyc3.cdn.digitaloceanspaces.com/…/preview.jpg",
  "aspectRatio": "16:9",
  "createdAt": "2026-04-16T10:42:31.413Z"
}

Verifying the signature

The X-GVM-Signature header is built as t=<unix-ms>,v1=<hex>. Compute the expected signature with the webhook secret you stored when creating the endpoint:

// Node
const crypto = require('crypto')
const [tPart, vPart] = req.header('X-GVM-Signature').split(',')
const t = tPart.split('=')[1]
const v1 = vPart.split('=')[1]
const expected = crypto
  .createHmac('sha256', WEBHOOK_SECRET)
  .update(t + '.' + JSON.stringify(req.body))
  .digest('hex')
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1))) {
  return res.status(401).send('bad signature')
}

Reject any payload whose t is older than 5 minutes to defeat replay attempts.

Retries

Non-2xx responses are retried with exponential backoff up to 8 attempts over ~24h. A persistent failure disables the endpoint and emails the account owner.