Rendobar POSTs JSON to your endpoint when a job changes status.
Set up a webhook
curl -X POST https://api.rendobar.com/webhook-endpoints \
-H "Authorization: Bearer rb_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production webhook",
"url": "https://your-server.com/webhooks/rendobar",
"subscribedEvents": ["job.completed", "job.failed"]
}'
Required: name (1–50 chars), url (must be HTTPS), subscribedEvents (≥ 1). The response includes a signing secret (whsec_...). Store it. You’ll verify every payload against it.
Manage endpoints (create, update, delete, test) via the API or the dashboard.
Events
| Event | When |
|---|
job.completed | Job finished successfully. Carries the unified output and cost |
job.failed | Job failed. Carries the unified error (code, message, detail, retryable) |
job.running | Job started executing on a runner |
batch.completed | Every job in a batch finished (success or fail) |
Payload
X-Rendobar-Signature: sha256=abc123...
X-Rendobar-Timestamp: 1707436815
X-Rendobar-Event: job.completed
X-Rendobar-Delivery: del_x1y2z3
X-Rendobar-Attempt: 1
The webhook carries the same contract as GET /jobs/. A job.completed payload includes the unified output object. The data field has the structured answer for analysis jobs, file.url is a signed, time-limited URL, and files lists every produced file. Read Job output for the full shape, the File type, and the four output patterns.
{
"event": "job.completed",
"jobId": "job_a1b2c3d4",
"output": {
"data": null,
"file": {
"url": "https://api.rendobar.com/dl/job_a1b2c3d4?token=...",
"path": "output.mp4",
"type": "video",
"size": 15234567,
"meta": { "format": "mp4", "width": 1920, "height": 1080, "durationMs": 127500 }
},
"files": [
{
"url": "https://api.rendobar.com/dl/job_a1b2c3d4?token=...",
"path": "output.mp4",
"type": "video",
"size": 15234567,
"meta": { "format": "mp4", "width": 1920, "height": 1080, "durationMs": 127500 }
}
],
"expiresAt": 1707440415000
},
"cost": { "amount": 50000000, "currency": "USD", "formatted": "$0.05" },
"timing": {
"createdAt": 1707436800000,
"startedAt": 1707436805000,
"completedAt": 1707436815000
}
}
The output shape is identical for every job type. A data-only job (such as extract.metadata) carries its answer in output.data with file null and files empty. A stream job carries the manifest as output.file and every segment in output.files. See Job output for each pattern.
For job.failed, the payload carries error instead of output. The error matches the GET /jobs error shape: code, message, detail (the process stderr tail, or null), and retryable.
{
"event": "job.failed",
"jobId": "job_a1b2c3d4",
"error": {
"code": "RUNNER_ERROR",
"message": "FFmpeg process exited with code 1",
"detail": "Conversion failed: Invalid data found when processing input",
"retryable": false
},
"timing": { "createdAt": 1707436800000, "startedAt": 1707436805000, "completedAt": 1707436810000 }
}
Verify the signature
The signature is HMAC-SHA256 over {timestamp}.{body} using your webhook secret. Timestamp-prefixed to prevent replays.
import { verifyWebhookSignature } from "@rendobar/sdk/webhooks";
// The signature covers `${timestamp}.${rawBody}` (raw string, not parsed JSON).
const ok = await verifyWebhookSignature(
`${timestamp}.${rawBody}`,
signature, // X-Rendobar-Signature header
process.env.WEBHOOK_SECRET,
);
if (!ok) throw new Error("Invalid signature");
Always use a timing-safe comparison (timingSafeEqual / hmac.compare_digest). String equality leaks signature bytes through timing.
Secret rotation
Rotation has a 24-hour window. During it, Rendobar sends both X-Rendobar-Signature (new secret) and X-Rendobar-Signature-Previous (old). Verify against either.
SSRF protection
URLs must be HTTPS. Delivery to private/reserved ranges (10.x, 172.16-31.x, 192.168.x, 127.x, ::1) is blocked.
Retries
If your endpoint doesn’t return 2xx within 10 seconds, Rendobar retries:
| Attempt | Delay |
|---|
| 1st | 5 s |
| 2nd | 25 s |
| 3rd | 125 s |
After three failures the delivery is marked failed. Inspect history:
curl https://api.rendobar.com/webhook-endpoints/YOUR_ENDPOINT_ID/deliveries \
-H "Authorization: Bearer rb_YOUR_KEY"
Best practices
- Return 200 fast. Process asynchronously. Long handlers trigger retries → duplicate deliveries.
- Deduplicate on
X-Rendobar-Delivery or jobId. Same event can arrive more than once.
- Verify every signature before reading the body.
See also
- Job lifecycle: what each status means before
job.completed fires
- Error codes: codes you’ll see inside
job.failed payloads
- FFmpeg: the job type that drives most webhook traffic
- MCP overview: alternative push channel for AI agent clients
- Changelog: webhook payload changes and new events