Images and video
Webhooks
Get an HTTPS callback when an image or video job completes or fails, instead of polling.
Set up
Add endpoints on the Webhooks page, or pass webhook_url on a single request. Every enabled endpoint receives job.completed and job.failed.
Payload
http
POST https://your-app.com/webhooks/sweetrouter
SweetRouter-Event: job.completed
SweetRouter-Delivery: cmg9a1...
SweetRouter-Signature: t=1791105133,v1=5f1c...
{
"id": "cmg9a1...",
"type": "job.completed",
"created_at": "2026-10-04T09:12:13.500Z",
"data": { "id": "cmg8x2k0d0001", "object": "job", "status": "completed", "outputs": [ ... ] }
}Verify the signature
Each request carries SweetRouter-Signature: t=timestamp,v1=hmac. Compute HMAC-SHA256 of timestamp.rawBody with your signing secret and compare. Reject anything older than 5 minutes.
node.js
import crypto from "node:crypto"
export function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")))
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex")
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300
return fresh && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))
}Retries
Respond with any 2xx within 10 seconds. Otherwise we retry after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, then stop. A delivery can arrive more than once, so dedupe on the delivery id.