Skip to content

Webhooks

A webhook tells your server when something happens, such as a video finishing. It saves you polling GET /v1/job/{id}. Webhooks are managed with the same API key as the rest of the API, under https://reignitor.com/api/webhooks.

Event Sent when
video.completed A render finished. The payload has the video URL.
video.failed A render failed. A render you cancel does not send this.
credits.low The account’s credit balance is running low.
credits.purchased Credits were added to the account.
subscription.created A plan subscription started.
subscription.canceled A plan subscription was cancelled.
user.signup The account was created.
user.onboarded The account finished onboarding.

GET /api/webhooks/events returns this list.

  1. Build an endpoint on your server that accepts POST requests with a JSON body and answers 2xx quickly. It must be reachable on the public internet. Private and local network addresses are refused.

  2. Subscribe it to an event. One webhook listens to one event; create one per event you need.

    Terminal window
    curl https://reignitor.com/api/webhooks/hooks \
    -H "Authorization: Bearer $REIGNITOR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
    "event": "video.completed",
    "webhook_url": "https://hooks.example.com/reignitor",
    "description": "Post finished videos to our CMS"
    }'
  3. Store the secret from the 201 response. You need it to check signatures.

  4. Send a test. POST /api/webhooks/hooks/{id}/test sends a signed ping event to your URL and tells you what your endpoint answered:

    { "delivered": true, "status": 200 }

Subscribing the same event and URL again does not create a duplicate. It returns the existing webhook with reused: true and switches it back on.

Every delivery is a POST with a JSON body:

{
"event": "video.completed",
"payload": {
"job_id": "7d2e4b10-5c3a-4f8e-a1b2-9c0d8e7f6a54",
"user_id": "3f1c2a9e-8b7d-4c1e-9f0a-2d6b5e4c3a21",
"output_url": "https://cdn.example.com/exports/7d2e4b10.mp4",
"canvas_id": null,
"scene_count": 4,
"scenes_failed": 0,
"credits_charged": 12
},
"emitted_at": "2026-09-25T10:15:00.000Z",
"delivery_id": "1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed"
}

video.failed carries job_id, user_id, canvas_id and a reason.

Match payload.job_id to the job_id you got from POST /v1/render.

And these headers:

Header Value
X-Reignitor-Event The event name.
X-Reignitor-Delivery A unique ID for this delivery. It stays the same when a delivery is retried.
X-Reignitor-Timestamp Unix time, in seconds, when the delivery was signed.
X-Reignitor-Signature sha256= and the hex HMAC-SHA256 of {timestamp}.{raw body}, keyed with your secret.

Check every delivery before you trust it:

  1. Read the raw request body, before any JSON parsing.
  2. Build the string {X-Reignitor-Timestamp}.{raw body}.
  3. Compute HMAC-SHA256 of it with your secret, as hex, and add sha256= in front.
  4. Compare it with X-Reignitor-Signature using a constant-time comparison.
  5. Reject the delivery if the timestamp is more than 5 minutes old.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyReignitorWebhook(rawBody, headers, secret) {
const timestamp = headers['x-banshea-timestamp'];
const received = headers['x-banshea-signature'] ?? '';
if (!timestamp || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = 'sha256=' + createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(received);
return a.length === b.length && timingSafeEqual(a, b);
}
  • Each delivery waits up to 10 seconds for your endpoint to answer.
  • A 5xx, a 429, a timeout or a network error is retried, up to 3 attempts in total, about a second apart.
  • Any other 4xx is not retried.
  • Retries keep the same X-Reignitor-Delivery. Use it to ignore a delivery you have already handled.
  • After 20 failed deliveries in a row, the webhook is switched off. GET /api/webhooks/hooks shows active: false and the last error in last_status. Fix your endpoint, then turn it back on with PATCH /api/webhooks/hooks/{id} and { "active": true }.

Answer 2xx as soon as you have stored the delivery, and do slow work afterwards.

Method Path What it does
GET /api/webhooks/events List event names and the signature scheme
GET /api/webhooks/hooks List your webhooks
POST /api/webhooks/hooks Create a webhook
PATCH /api/webhooks/hooks/{id} Pause, resume, or change the URL or description
DELETE /api/webhooks/hooks/{id} Delete a webhook
POST /api/webhooks/hooks/{id}/test Send a signed ping

An account can have up to 25 webhooks. Full request and response shapes are in the endpoint reference.