Webhooks
Webhooks let you generate thumbnails asynchronously. Instead of waiting for the response, ThumbAPI sends the result to your callback URL when the thumbnail is ready.
Available on Pro and Business plans.
How It Works
- You send a generate request with a
webhookUrlfield - The API returns
202 Acceptedimmediately with ajobId - When the thumbnail is ready, ThumbAPI POSTs the result to your
webhookUrl
Sending a Webhook Request
Add webhookUrl to your normal generate request:
curl -X POST https://api.thumbapi.dev/v1/generate \
-H "Authorization: Bearer tb_live_abc123" \
-H "Content-Type: application/json" \
-d '{
"title": "How to Build a SaaS",
"format": "youtube",
"imageStyle": "faceless",
"webhookUrl": "https://your-app.com/api/webhooks/thumbapi"
}'
Immediate Response (202)
{
"jobId": "job_a1b2c3d4e5",
"status": "processing",
"webhookUrl": "https://your-app.com/api/webhooks/thumbapi"
}
Webhook Payload
When the thumbnail is ready, ThumbAPI sends a POST to your URL:
{
"event": "generation.completed",
"jobId": "job_a1b2c3d4e5",
"data": {
"image": "data:image/webp;base64,UklGRp4HAA...",
"format": "youtube",
"dimensions": { "width": 1280, "height": 720 }
},
"timestamp": "2026-04-27T14:30:00Z"
}
Failed Generation
{
"event": "generation.failed",
"jobId": "job_a1b2c3d4e5",
"error": "Image generation timed out",
"timestamp": "2026-04-27T14:30:45Z"
}
Handling Webhooks
Your endpoint must return 200 within 10 seconds. If it doesn't, ThumbAPI retries up to 3 times with exponential backoff.
Node.js / Express Example
app.post("/api/webhooks/thumbapi", (req, res) => {
const { event, jobId, data, error } = req.body;
if (event === "generation.completed") {
// Save the thumbnail
saveImage(jobId, data.image);
} else if (event === "generation.failed") {
console.error(`Job ${jobId} failed: ${error}`);
}
res.sendStatus(200); // Always acknowledge
});
Security
Verify webhook authenticity by checking the X-ThumbAPI-Signature header. This is an HMAC-SHA256 signature of the request body using your API key as the secret.
import crypto from "crypto";
function verifyWebhook(body, signature, apiKey) {
const expected = crypto
.createHmac("sha256", apiKey)
.update(JSON.stringify(body))
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
Next Steps
- Rate limits — webhook requests count toward your quota
- Error codes — handling failed generations
- SDKs — webhook support is built into the official SDKs