Documentation Index
Fetch the complete documentation index at: https://rendobar.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Rendobar POSTs JSON to your endpoint when a job changes status. Available on all plans, including Free.
Set up a webhook
curl -X POST https://api.rendobar.com/webhook-endpoints \
-H "Authorization: Bearer rb_live_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. Includes output URL + metadata |
job.failed | Job failed. Includes error.code and error.message |
job.running | Job started executing on a provider |
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
{
"event": "job.completed",
"jobId": "job_a1b2c3d4",
"result": {
"url": "https://r2.rendobar.com/...",
"metadata": {
"durationMs": 127500,
"width": 1920,
"height": 1080,
"fileSize": 15234567
}
},
"cost": { "nanodollars": 50000000, "formatted": "$0.05" },
"timing": {
"createdAt": 1707436800000,
"startedAt": 1707436805000,
"completedAt": 1707436815000
}
}
For job.failed, replace result with error:
{
"event": "job.failed",
"jobId": "job_a1b2c3d4",
"error": { "code": "PROVIDER_ERROR", "message": "FFmpeg process exited with code 1" },
"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 { createHmac, timingSafeEqual } from "crypto";
function verifyWebhook(body, signature, timestamp, secret) {
const message = `${timestamp}.${body}`;
const expected = createHmac("sha256", secret).update(message, "utf8").digest("hex");
const received = signature.replace("sha256=", "");
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(received, "hex"));
}
app.post("/webhooks/rendobar", (req, res) => {
const ok = verifyWebhook(
req.rawBody, // raw string, not parsed JSON
req.headers["x-rendobar-signature"],
req.headers["x-rendobar-timestamp"],
process.env.WEBHOOK_SECRET
);
if (!ok) return res.status(401).send("Invalid signature");
// process req.body...
res.status(200).send("OK");
});
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_live_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