Webhook Payload
Understand the webhook delivery format, signature verification, retry schedule, and auto-disable behavior.
Webhook Payload
This page describes the format and behavior of webhook deliveries. Webhooks are not a separate API endpoint you call -- instead, RenderIO sends HTTP POST requests to your configured URL when commands complete.
Delivery format
When a command finishes processing (either SUCCESS or FAILED), RenderIO sends a POST request to your webhook URL with the following payload:
{
data: CommandPollResponse;
timestamp: number;
}| Field | Type | Description |
|---|---|---|
data | CommandPollResponse | The full command result, identical to what GET /api/v1/commands/:commandId returns. |
timestamp | number | Unix timestamp (in milliseconds) of when the webhook was dispatched. |
Headers
Every webhook delivery includes the following headers:
| Header | Value | Description |
|---|---|---|
Content-Type | application/json | The payload is always JSON. |
User-Agent | RenderIO-Webhook/1.0 | Identifies the request as a RenderIO webhook delivery. |
X-Webhook-Signature | string | HMAC-SHA256 hex digest of the request body. Only present if you configured a signing secret. |
Signature verification
If you set a secret when configuring your webhook, every delivery includes an X-Webhook-Signature header. The signature is computed as an HMAC-SHA256 hex digest of the raw JSON request body using your secret as the key.
Always verify the signature before processing the payload to ensure the request genuinely came from RenderIO.
Node.js verification example
import crypto from "node:crypto";
function verifyWebhookSignature(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex"),
);
}
// In your webhook handler:
app.post("/webhooks/renderio", (req, res) => {
const rawBody = req.rawBody; // raw request body as string
const signature = req.headers["x-webhook-signature"];
const secret = process.env.RENDERIO_WEBHOOK_SECRET;
if (!verifyWebhookSignature(rawBody, signature, secret)) {
return res.status(401).send("Invalid signature");
}
const { data, timestamp } = JSON.parse(rawBody);
console.log(`Command ${data.command_id} finished with status: ${data.status}`);
// Process the webhook payload...
res.status(200).send("OK");
});Python verification example
import hashlib
import hmac
import os
import json
def verify_webhook_signature(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your webhook handler (Flask example):
@app.route("/webhooks/renderio", methods=["POST"])
def handle_webhook():
raw_body = request.get_data()
signature = request.headers.get("X-Webhook-Signature", "")
secret = os.environ["RENDERIO_WEBHOOK_SECRET"]
if not verify_webhook_signature(raw_body, signature, secret):
return "Invalid signature", 401
payload = json.loads(raw_body)
data = payload["data"]
print(f"Command {data['command_id']} finished with status: {data['status']}")
# Process the webhook payload...
return "OK", 200Successful delivery
A delivery is considered successful when your endpoint returns any 2xx HTTP status code. Any other status code or a connection failure is treated as a failed delivery.
Retry schedule
If a delivery fails, RenderIO retries with exponential backoff. The retry intervals are:
| Attempt | Delay after failure |
|---|---|
| 1 | Immediate |
| 2 | 5 seconds |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 5 hours |
| 7 | 10 hours |
| 8 | 10 hours |
After 8 consecutive failed attempts, the webhook is auto-disabled.
Auto-disable behavior
When a webhook accumulates 8 consecutive delivery failures, RenderIO automatically deactivates it:
- The
is_activefield is set tofalse - The
disabled_attimestamp is recorded - No further deliveries are attempted until you re-enable the webhook
To re-enable a disabled webhook, call PUT /api/v1/webhook-config with your URL. This resets the failure counter and reactivates delivery.
You can check the current failure count and status at any time with GET /api/v1/webhook-config.
Per-command webhook URL
In addition to the account-level webhook configuration, you can specify a webhook_url on individual command requests (e.g., in the body of POST /api/v1/run-ffmpeg-command or POST /api/v1/presets/:presetId/execute). When set, this per-command URL overrides the global webhook configuration for that specific command.
Per-command webhook URLs use the same payload format and signature verification as the global webhook. However, they do not affect the global failure counter or auto-disable behavior.