Skip to main content

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

EventWhen
job.completedJob finished successfully. Includes output URL + metadata
job.failedJob failed. Includes error.code and error.message
job.runningJob started executing on a provider
batch.completedEvery 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:
AttemptDelay
1st5 s
2nd25 s
3rd125 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