Receive real-time event notifications
Webhooks allow you to receive real-time notifications when events occur in your account. Configure your webhook endpoint in the dashboard settings.
| Event | Description |
|---|---|
| image.completed | Image generation completed successfully |
| image.failed | Image generation failed |
| video.completed | Video generation completed successfully |
| video.failed | Video generation failed |
| credits.updated | User credits changed (purchase, usage, refund) |
| subscription.created | New subscription created |
| subscription.updated | Subscription plan changed |
| subscription.cancelled | Subscription was cancelled |
All webhook payloads follow a consistent structure:
{
"id": "evt_abc123xyz",
"type": "video.completed",
"createdAt": "2026-02-04T12:00:00Z",
"data": {
"taskId": "task_xyz789abc",
"userId": "user_123",
"videoUrl": "https://storage.example.com/videos/task_xyz789abc.mp4",
"duration": 5,
"creditsUsed": 50
}
}{
"id": "evt_img456",
"type": "image.completed",
"createdAt": "2026-02-04T12:00:00Z",
"data": {
"taskId": "img_abc123",
"userId": "user_123",
"imageUrl": "https://storage.example.com/images/img_abc123.png",
"model": "flux-pro",
"creditsUsed": 10
}
}{
"id": "evt_cred789",
"type": "credits.updated",
"createdAt": "2026-02-04T12:00:00Z",
"data": {
"userId": "user_123",
"previousBalance": 100,
"newBalance": 90,
"change": -10,
"reason": "image_generation"
}
}All webhook requests include a signature header to verify authenticity. Always verify the signature before processing events.
| Header | Description |
|---|---|
| X-Webhook-Signature | HMAC-SHA256 signature of the payload |
| X-Webhook-Timestamp | Unix timestamp when the webhook was sent |
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, timestamp, secret) {
// Check timestamp to prevent replay attacks (5 minute window)
const currentTime = Math.floor(Date.now() / 1000);
if (currentTime - parseInt(timestamp) > 300) {
throw new Error('Webhook timestamp too old');
}
// Compute expected signature
const signedPayload = `${timestamp}.${JSON.stringify(payload)}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Compare signatures
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)) {
throw new Error('Invalid signature');
}
return true;
}
// Usage in Express route
app.post('/webhook', (req, res) => {
try {
verifyWebhookSignature(
req.body,
req.headers['x-webhook-signature'],
req.headers['x-webhook-timestamp'],
process.env.WEBHOOK_SECRET
);
// Process the webhook event
const { type, data } = req.body;
console.log('Received event:', type, data);
res.status(200).json({ received: true });
} catch (error) {
res.status(400).json({ error: error.message });
}
});Return a 2xx response within 30 seconds. Process events asynchronously if needed.
Use the event 'id' field to deduplicate. Webhooks may be retried on failure.
Always verify the webhook signature before trusting the payload.
Webhook endpoints must use HTTPS for security.
Keep logs of received webhooks for debugging and auditing.
If your endpoint returns a non-2xx response, we will retry the webhook:
| Attempt | Delay |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry (final) | 24 hours |