Webhook payloads and signature verification
batch.completed, job.completed and job.failed payloads, HMAC-SHA256 signature verification in Node, and the retry schedule.
Events
POST /v1 has finished, whatever the outcome. This is the event to collect on: the job has settled and its rows are ready to read.webhook_url is refused with 403 plan_limit, so poll instead.Payload
Two ids appear, and they are not interchangeable. batch_id is the id POST /v1 answered with, and the one GET /v1/{job_id} accepts. job_id in a job event identifies a single video inside it; reading it as a job returns 404.
batch.completed, read GET /v1/{batch_id} to collect them. That keeps the read-once rule in one place and means a leaked webhook body exposes nothing extracted.Signing
Every delivery carries X-TubeExtract-Signature, an HMAC-SHA256 of the raw body using the endpoint’s signing secret, and X-TubeExtract-Timestamp in Unix seconds. The signed string is {timestamp}.{body}, so a captured body cannot be replayed later under a new timestamp. Compare with a constant-time function and reject anything older than five minutes.
Each endpoint has its own secret, shown on the webhooks screen. Rotating it there keeps the previous one valid for 24 hours, so a deploy has time to catch up.
Deliveries also carry a Web Bot Auth signature (an RFC 9421 HTTP message signature in the Signature, Signature-Input and Signature-Agent headers), which lets a firewall or CDN that supports it, Cloudflare included, confirm a request really came from TubeExtract without knowing your endpoint’s secret. The public key is at /.well-known/http-message-signatures-directory. The HMAC above is still what verifies a payload is intact and meant for your endpoint.
webhook_url passed on POST /v1 is registered as an endpoint the first time it is used, with its own secret. From then on it receives every event in the workspace, not only the ones for that call. Remove it on the webhooks screen when you no longer want it.Retries
Anything other than a 2xx is retried. A delivery gets five attempts in all: immediately, then 30 seconds, 2 minutes, 10 minutes and 30 minutes after each failure, about 45 minutes end to end. Each delivery, with its attempt count and last response code, is listed on the webhooks screen, where a failed delivery can be replayed by hand without re-running the extraction.
job_id, or batch_id for batch.completed.