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; nowebhook_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:
{ "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 awebhook_url in your job request:
Webhook Payload
When a job completes, Tornado sends aPOST 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 emittype: "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
Whenenable_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:
To enable progress webhooks:
Webhook Behavior
Handling Webhooks
Node.js (Express)
Python (Flask)
Best Practices
Respond Quickly
Respond Quickly
Return a 2xx status promptly. The per-job outcome sender uses a 10-second request timeout; queue longer processing asynchronously.
Verify Source
Verify Source
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.Idempotency
Idempotency
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.Retry Logic
Retry Logic
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 thewebhook_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-jobjob_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.