Where webhooks are available
- Supported: the following Generate endpoints —
POST /api/v1/generate-and-post,/clipper/youtube,/videos/text-to-video,/videos/image-to-videoand/videos/ai-influencer,/blog-to-videoand/videos/magic— with awebhook_urlin the request body. - There is no webhook registration API — the URL is set per request, so different customers or pipelines can use different endpoints.
Setting the URL
curl -X POST https://api.reelsbuilder.ai/api/v1/clipper/youtube \
-H "Authorization: Bearer $REELSBUILDER_API_KEY" \
-H "Idempotency-Key: acme-webinar-0915" \
-H "Content-Type: application/json" \
-d '{
"youtube_url": "https://www.youtube.com/watch?v=VIDEO_ID",
"clip_count": 3,
"webhook_url": "https://your-app.example.com/webhooks/reelsbuilder",
"agent_run_id": "run-42"
}'Requirements for webhook_url:
httpsonly (anything else returns400 INPUT_INVALID).- The host must resolve to a public address (private, loopback and link-local addresses are skipped).
- Redirects are not followed — respond directly from the URL you register.
Delivery
When the job reaches completed, failed or dead_lettered, ReelsBuilder sends one POST with these headers:
Content-Type: application/json
User-Agent: ReelsBuilder-Webhook/1.0
X-ReelsBuilder-Event: generation.job.terminal
X-ReelsBuilder-Signature: t=1791419587,v1=5f2c…Body:
{
"event": "job.completed", // or "job.failed"
"job_id": "6a0f...",
"status": "completed", // completed | failed | dead_lettered
"video_id": "6a0f...",
"video_url": "https://...mp4", // null unless completed (and null for private delivery)
"video_urls": ["https://...mp4"], // completed only: every delivered file (all clips)
"title": "3 signs your pipeline review is broken",
"description": "... #revops #b2bsales",
"duration_sec": 30.1,
"error": null, // { code, message, retryable } when not completed
"agent_run_id": "run-42", // null if you did not send one
"poll_url": "/api/v1/jobs/6a0f...",
"timestamp": "2026-10-06T12:00:00.000Z"
}Cancelled jobs send nothing. Jobs using private delivery never carry media links in the callback; poll the job for a fresh signed link.
Verifying a callback
Every callback is signed with your account's webhook secret. Get it once (free) and store it with your other secrets:
curl https://api.reelsbuilder.ai/api/v1/webhook-secret \
-H "Authorization: Bearer $REELSBUILDER_API_KEY"
# -> { "data": { "secret": "whsec_...", "header": "X-ReelsBuilder-Signature", ... } }The header is t=<unix seconds>,v1=<hex>, where v1 is HMAC-SHA256 of <t>.<raw body> with your secret. Compute it over the raw request body (before JSON parsing), compare in constant time, and reject timestamps more than 5 minutes old.
import crypto from "node:crypto";
app.post("/webhooks/reelsbuilder", express.raw({ type: "application/json" }), (req, res) => {
const header = req.get("X-ReelsBuilder-Signature") ?? "";
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const t = Number(parts.t);
const expected = crypto
.createHmac("sha256", process.env.REELSBUILDER_WEBHOOK_SECRET)
.update(t + "." + req.body)
.digest("hex");
const valid =
Math.abs(Date.now() / 1000 - t) < 300 &&
parts.v1?.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1, "hex"), Buffer.from(expected, "hex"));
if (!valid) return res.sendStatus(400);
res.sendStatus(200); // acknowledge fast, then work
const event = JSON.parse(req.body.toString());
if (event.status === "completed") handleFinishedVideo(event.video_urls, event.title, event.description);
});Retry policy
- Each attempt times out after 10 seconds.
- Up to 3 attempts: immediately, then after a 30-second wait, then after a further 120-second wait (about 2.5 minutes in total).
- Any 2xx response stops retries.
- There is no manual replay. If all attempts fail, poll the job.
Best practices
- Respond 2xx quickly and do the work asynchronously.
- Make your handler idempotent by
job_id— the same job can be delivered more than once. - Keep polling as a fallback: if no callback arrives within a few minutes of the expected completion, read the job directly.
- Use
agent_run_idto correlate the callback with your own run.