IntermediateUpdated Dec 10, 2025
Webhook Configuration
Receive async results for long-running tasks with secure webhook delivery and HMAC signature verification.
MP
Maya Patel
API Architect
7 min read
Why Webhooks?
Long-running tasks (video generation, batch processing) can take minutes. Instead of polling, webhooks push results to your server when ready.
Setting Up a Webhook Endpoint
Express.js Example
javascript
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
app.post('/webhook/abstrakt', (req, res) => {
// Verify signature
const signature = req.headers['x-abstrakt-signature'];
const payload = JSON.stringify(req.body);
const expectedSignature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if (signature !== expectedSignature) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the webhook
const { request_id, status, result } = req.body;
if (status === 'completed') {
console.log(`Job ${request_id} completed!`);
console.log(`Result: ${result.items[0].url}`);
// Save to database, notify user, etc.
}
res.json({ received: true });
});
app.listen(3000);Python Flask Example
python
from flask import Flask, request, jsonify
import hmac
import hashlib
import os
app = Flask(__name__)
WEBHOOK_SECRET = os.environ['WEBHOOK_SECRET']
def verify_signature(payload, signature):
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
@app.route('/webhook/abstrakt', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Abstrakt-Signature')
if not verify_signature(request.data, signature):
return jsonify({'error': 'Invalid signature'}), 401
data = request.json
if data['status'] == 'completed':
# Process completed job
save_result(data['request_id'], data['result'])
return jsonify({'received': True})Configuring Webhooks in API Calls
python
result = client.submit("fal-ai/minimax/video-01", {
"input": {
"prompt": "A beautiful sunset over the ocean"
},
"webhook_url": "https://your-server.com/webhook/abstrakt",
"webhook_secret": "your_secret_here"
})
print(f"Job submitted: {result.request_id}")
# Result will be POSTed to your webhook when readyWebhook Payload Format
json
{
"request_id": "abc123",
"status": "completed",
"result": {
"items": [
{
"url": "https://cdn.abstrakt.one/...",
"content_type": "video/mp4"
}
]
},
"metrics": {
"inference_time": 45.2,
"queue_time": 2.1
},
"timestamp": "2025-01-12T10:30:00Z"
}Handling Failures
javascript
app.post('/webhook/abstrakt', (req, res) => {
const { request_id, status, error } = req.body;
if (status === 'failed') {
console.error(`Job ${request_id} failed: ${error.message}`);
// Retry logic, notify user, etc.
}
res.json({ received: true });
});Retry Policy
If your webhook fails, we retry:
- Immediate retry
- 1 minute delay
- 5 minutes delay
- 15 minutes delay
- 1 hour delay (final)
Return 2xx status to acknowledge receipt.
Testing Webhooks Locally
Use ngrok for local development:
ngrok http 3000
Use the ngrok URL as your webhook endpoint during testing.
Dashboard Configuration
You can also configure webhooks in the dashboard:
- Go to Settings → Webhooks
- Add your endpoint URL
- Set a webhook secret
- Select events to receive
Best Practices
- Always verify signatures - Prevent spoofed requests
- Return quickly - Process async, respond fast
- Handle idempotency - Same webhook may arrive twice
- Log everything - Debug issues easily
- Use HTTPS - Secure transmission
Next Steps
- Learn REST API basics
- Scale with batch processing
- Implement content safety
#webhooks#async#api#integration