Skip to main content

Overview

Webhooks allow you to receive HTTP notifications when jobs complete, eliminating the need for polling.

Organization endpoints (dashboard)

Create an endpoint in Dashboard → Webhooks → Endpoints and choose the events it receives. It applies automatically to jobs submitted with any API key in your organization; no webhook_url is needed in each request. Completed jobs emit job.completed; failures and warnings emit job.failed. Events are usually sent after the next dispatcher poll (about 20 seconds, longer during a backlog). A new endpoint does not receive jobs completed before it was registered. New endpoints offer Simple key verification. Save the key shown once at creation on your receiving server. Accept a request only when its X-Tornado-Webhook-Key header matches that saved key; reject missing or incorrect values. Keep the key private. For example, in a FastAPI handler:
Org events use { "event": "job.completed", "delivery_id": "…", "at": "…", "data": { "job_id": "…" } }. HMAC signature remains available and existing endpoints retain their signature mode. The shared key verifies possession of a secret; HMAC additionally binds the payload and timestamp. Deduplicate deliveries in either mode. Organizations with no endpoint retain their current behavior. Explicit per-job callbacks below remain independent; configuring both can send two notifications.

Per-job setup

Include a webhook_url in your job request:

Webhook Payload

When a job completes, Tornado sends a POST request to your webhook_url with a JSON payload. Here’s what your server will receive:

Job Started (Processing)

Sent when a worker picks up the job and begins processing:

Single Job Completion

s3_url/subtitle_url/thumbnail_url use the selected delivery backend. Newly signed URLs generally request 24 hours, but a supplied Azure SAS retains its own expiry and Drive access follows its permissions. Keys remain in the payload alongside nullable URL fields; a key is not itself a download URL.

Job Failed

Technical failures emit type: "job_failed", status: "failed". Content warnings emit a separate type: "job_warning", status: "warning" payload with the same job/error fields; they are not silent. Both can include failure_kind and a structured failure object, or null when no typed verdict exists.

Job Skipped

Sent when a job is skipped because the content cannot be processed. This happens for audio-only Spotify episodes that are protected by Widevine DRM and have no video stream available. Skipped jobs are classified as warnings, not errors — they represent content limitations, not technical failures.
Batch completion accounts for completed, failed and skipped episodes. Skipped episodes have a separate counter; do not treat them as successful downloads.

Batch Completion

When all episodes in a batch are done:

Progress Webhooks

When enable_progress_webhook: true is set, the worker attempts updates at applicable processing stages. Some paths skip stages, and these notifications do not have the outcome retry/signing guarantee:
Progress stages and percentages: To enable progress webhooks:

Webhook Behavior

Handling Webhooks

Node.js (Express)

Python (Flask)

Best Practices

Return a 2xx status promptly. The per-job outcome sender uses a 10-second request timeout; queue longer processing asynchronously.
When webhook signing is enabled for your key, verify X-Tornado-Signature against the exact raw request body before processing. Do not treat a missing signature as verified. See the signing contract for your configured webhook family.
Handle duplicate webhooks gracefully. Deduplicate by event type and job ID for per-job outcomes, or event type and batch ID for batch outcomes. Organization deliveries have their own delivery_id; a processing event must not suppress a later completion event.
Per-job outcome notifications use three total attempts by default (the initial attempt plus up to two retries). Transport errors, HTTP 5xx, 408 and 429 are retryable; other HTTP errors are not retried by this path. The attempt budget is configurable. Batch and organization-level notifications have separate delivery paths. Ensure your handler tolerates duplicates.

Testing Webhooks

Use a service like webhook.site or ngrok to test webhooks locally:

Delivery families and signing

This page describes the webhook_url supplied with a media job or batch. Its event types use names such as job_completed and batch_completed. Endpoints configured for an organization in the dashboard use their own event contract; do not rename one family’s events to match another. When enabled, the media-job signature header has the form t=<unix-seconds>,v1=<hex-hmac>. Verification must use the raw bytes received and reject timestamps outside your accepted replay window. Per-job outcome retries are signed at send time, so a repeated delivery can carry a new timestamp and signature. Inspect webhook_status, webhook_attempts and webhook_last_error on the job where available. A completed media job does not prove that your webhook endpoint accepted its notification.

Multi-clip job completion

A per-job job_completed webhook for a request with clips also includes clip_files in request order. Each entry contains clip_start, clip_end, s3_key, s3_url and file_size. One webhook is sent after all clips upload; the main s3_url points to the first clip. See several clips from one video.