Webhooks
Get real-time notifications when generation jobs complete using webhooks
Overview
Webhooks allow you to receive HTTP callbacks when asynchronous operations complete, instead of polling the API. This is essential for long-running operations like video generation (5-15 minutes) or 3D generation (10-20 minutes).
Benefits
- Eliminate polling and reduce API calls by 95%+
- Get instant notifications when jobs complete
- Scale efficiently with thousands of concurrent jobs
- Automatic retry logic with exponential backoff
Setting Up Webhooks
1. Create Webhook Endpoint
First, create an endpoint in your application to receive webhook events:
// Express.js example
import express from 'express';
import crypto from 'crypto';
const app = express();
app.use(express.json());
app.post('/api/webhooks/wazza', async (req, res) => {
// 1. Verify webhook signature
const signature = req.headers['x-wazza-signature'];
const isValid = verifyWebhookSignature(
req.body,
signature,
process.env.WAZZA_WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// 2. Process the webhook event
const { event, jobId, status, output, error } = req.body;
switch (event) {
case 'job.completed':
console.log(`Job ${jobId} completed`, output);
// Update your database, notify users, etc.
break;
case 'job.failed':
console.log(`Job ${jobId} failed`, error);
// Handle failure, notify user, retry, etc.
break;
case 'job.processing':
console.log(`Job ${jobId} is processing`);
break;
}
// 3. Return 200 to acknowledge receipt
res.status(200).json({ received: true });
});
function verifyWebhookSignature(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
const digest = hmac.update(JSON.stringify(payload)).digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(digest)
);
}
app.listen(3000);2. Register Webhook URL
Register your webhook URL in the Wazza Console or via API:
// Register webhook via API
const response = await fetch('https://api.wazza.ai/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${WAZZA_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
url: 'https://your-domain.com/api/webhooks/wazza',
events: ['job.completed', 'job.failed', 'job.processing'],
secret: 'your-webhook-secret' // Used for signature verification
})
});
const webhook = await response.json();
console.log('Webhook ID:', webhook.id);3. Use Webhook in Requests
Include the webhook URL when creating generation jobs:
import WazzaEngine from '@wazza/engine';
const wazza = new WazzaEngine({
apiKey: process.env.WAZZA_API_KEY
});
// Create job with webhook
const response = await wazza.generate({
provider: 'openai',
model: 'sora-2-pro',
prompt: 'A cinematic video of a sunset over mountains',
webhookUrl: 'https://your-domain.com/api/webhooks/wazza',
webhookEvents: ['job.completed', 'job.failed']
});
console.log('Job created:', response.jobId);
// No need to poll - you'll receive a webhook when complete!Webhook Events
Wazza Engine sends the following webhook events:
job.completed
Sent when a generation job completes successfully
{
"event": "job.completed",
"jobId": "job_abc123",
"status": "completed",
"output": {
"url": "https://cdn.wazza.ai/outputs/abc123.mp4",
"width": 1920,
"height": 1080,
"duration": 10,
"format": "mp4"
},
"metadata": {
"provider": "openai",
"model": "sora-2-pro",
"creditsUsed": 15
},
"timestamp": "2025-10-22T10:30:00Z"
}job.failed
Sent when a generation job fails
{
"event": "job.failed",
"jobId": "job_abc123",
"status": "failed",
"error": {
"code": "CONTENT_POLICY_VIOLATION",
"message": "Content violates safety policy"
},
"timestamp": "2025-10-22T10:30:00Z"
}job.processing
Sent periodically with progress updates (optional)
{
"event": "job.processing",
"jobId": "job_abc123",
"status": "processing",
"progress": {
"percent": 45,
"stage": "rendering",
"estimatedTimeRemaining": 300
},
"timestamp": "2025-10-22T10:30:00Z"
}Security
Signature Verification
Always verify webhook signatures to ensure requests come from Wazza:
import crypto from 'crypto';
function verifyWazzaWebhook(req) {
const signature = req.headers['x-wazza-signature'];
const timestamp = req.headers['x-wazza-timestamp'];
const body = JSON.stringify(req.body);
// 1. Check timestamp to prevent replay attacks
const requestTime = parseInt(timestamp);
const currentTime = Math.floor(Date.now() / 1000);
if (Math.abs(currentTime - requestTime) > 300) { // 5 minutes
throw new Error('Webhook timestamp too old');
}
// 2. Verify HMAC signature
const payload = `${timestamp}.${body}`;
const hmac = crypto.createHmac('sha256', WEBHOOK_SECRET);
const expectedSignature = hmac.update(payload).digest('hex');
if (!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
)) {
throw new Error('Invalid webhook signature');
}
return true;
}IP Allowlisting (Optional)
For additional security, restrict webhook requests to Wazza's IP ranges:
Wazza webhook IPs (staging and production):
52.89.214.238, 34.212.75.30, 54.218.53.128, 52.32.178.7Retry Logic
Wazza automatically retries failed webhook deliveries with exponential backoff:
After 5 failed attempts, the webhook is marked as failed and you'll receive an email notification. You can manually retry from the dashboard or fetch the job status via API.
Testing Webhooks
Local Testing with ngrok
# 1. Install ngrok
npm install -g ngrok
# 2. Start your local server
npm run dev
# 3. Create tunnel to localhost
ngrok http 3000
# 4. Use the ngrok URL as your webhook endpoint
# Example: https://abc123.ngrok.io/api/webhooks/wazzaManual Testing
Trigger test webhook events from the Wazza Console:
- Go to Dashboard → Webhooks
- Select your webhook
- Click "Send Test Event"
- Choose event type (completed, failed, processing)
- Verify your endpoint receives and processes the event
Best Practices
1. Respond Quickly
- Return 200 status within 5 seconds
- Process events asynchronously (use job queue)
- Don't make external API calls in webhook handler
2. Handle Duplicate Events
- Webhooks may be delivered multiple times (idempotency)
- Use jobId to deduplicate events
- Store processed event IDs in database
3. Secure Your Endpoint
- Always verify webhook signatures
- Check timestamp to prevent replay attacks
- Use HTTPS endpoints only
- Consider IP allowlisting for sensitive data
4. Monitor Webhook Health
- Track webhook delivery success rate
- Set up alerts for failed deliveries
- Log all webhook events for debugging
- Use webhook dashboard to monitor status