Webhooks - Batch API
Receive notifications when transcriptions complete instead of polling.
Overview
Webhooks allow you to:
- Eliminate status polling
- Reduce API calls
- Get instant notifications
- Build event-driven workflows
Setup
1. Configure Webhook URL
Provide webhook_url when uploading:
curl -X POST https://api.scriptix.io/api/v3/stt \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "language=en" \
-F "webhook_url=https://yourapp.com/webhook" \
-F "audio_file=@audio.mp3"
2. Receive Webhook
Your endpoint receives POST request when transcription completes:
POST /webhook HTTP/1.1
Host: yourapp.com
Content-Type: application/json
X-Scriptix-Signature: sha256=abc123...
{
"event": "transcription.completed",
"timestamp": "2025-01-17T10:30:00Z",
"data": {
"id": "stt_abc123",
"status": "completed",
"document_id": 456
}
}
Webhook Events
| Event | Trigger |
|---|---|
transcription.completed | Transcription finished successfully |
transcription.failed | Transcription failed with error |
Webhook Payload
{
"event": "transcription.completed",
"timestamp": "2025-01-17T10:30:00Z",
"data": {
"id": "stt_abc123",
"status": "completed",
"document_id": 456,
"duration_seconds": 3600,
"language": "en"
}
}
Webhook Signature
Verify webhook authenticity using X-Scriptix-Signature header:
Python Verification
import hmac
import hashlib
def verify_webhook(payload, signature, secret):
"""Verify webhook signature."""
expected = hmac.new(
secret.encode(),
payload.encode(),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
# Usage
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.data.decode()
signature = request.headers.get('X-Scriptix-Signature')
if not verify_webhook(payload, signature, WEBHOOK_SECRET):
return 'Invalid signature', 401
data = request.json()
if data['event'] == 'transcription.completed':
job_id = data['data']['id']
document_id = data['data']['document_id']
# Process completed transcription
process_completed(job_id, document_id)
return 'OK', 200
Node.js Verification
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(`sha256=${expected}`),
Buffer.from(signature)
);
}
app.post('/webhook', (req, res) => {
const payload = JSON.stringify(req.body);
const signature = req.headers['x-scriptix-signature'];
if (!verifyWebhook(payload, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const { event, data } = req.body;
if (event === 'transcription.completed') {
processCompleted(data.id, data.document_id);
}
res.send('OK');
});
Best Practices
1. Return 200 OK Quickly
Process webhook asynchronously:
@app.route('/webhook', methods=['POST'])
def webhook():
data = request.json()
# Queue for async processing
queue.enqueue(process_webhook, data)
# Return immediately
return 'OK', 200
def process_webhook(data):
# Long-running processing here
pass
2. Implement Idempotency
Handle duplicate webhooks:
processed_webhooks = set()
def process_webhook(data):
job_id = data['data']['id']
if job_id in processed_webhooks:
return # Already processed
# Process webhook
handle_transcription(job_id)
processed_webhooks.add(job_id)
3. Retry Failed Webhooks
Scriptix retries failed webhooks:
- 3 retry attempts
- Exponential backoff (1min, 5min, 15min)
Always return 200 OK for successful processing.
Testing Webhooks
Use Webhook Testing Tools
- Webhook.site - Get test URL
- ngrok - Expose local server
# Expose local server
ngrok http 3000
# Use ngrok URL in upload
-F "webhook_url=https://abc123.ngrok.io/webhook"
Test Payload
curl -X POST https://yourapp.com/webhook \
-H "Content-Type: application/json" \
-H "X-Scriptix-Signature: sha256=test123" \
-d '{
"event": "transcription.completed",
"timestamp": "2025-01-17T10:30:00Z",
"data": {
"id": "stt_test123",
"status": "completed",
"document_id": 999
}
}'
Troubleshooting
Webhook Not Received
Checklist:
- ✅ URL publicly accessible?
- ✅ HTTPS enabled? (required)
- ✅ Firewall allows Scriptix IPs?
- ✅ Returns 200 OK?
- ✅ Response time < 30 seconds?
Signature Verification Fails
Common issues:
- Using wrong webhook secret
- Incorrect payload serialization
- Timing attack in comparison
Related
- Upload Files
- Check Status - Fallback to polling