Webhooks
Receive real-time notifications when transcription jobs complete or fail.
Instead of polling for job status, you can register webhook URLs to receive HTTP POST notifications when events occur. This is the recommended approach for production applications using async transcription.
Event Types
- job.completed — A transcription job finished successfully
- job.failed — A transcription job failed with an error
- job.progress — Periodic progress updates while a job is processing
- * — Subscribe to all events
Registering a Webhook
Create a webhook by specifying the URL and the events you want to receive:
curl "https://asr.lesan.ai/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/lesan",
"events": ["job.completed", "job.failed"],
"secret": "whsec_abc123...",
"description": "Production transcription notifications"
}'
# Response:
# {
# "id": "wh_abc123",
# "object": "webhook",
# "url": "https://your-app.com/webhooks/lesan",
# "events": ["job.completed", "job.failed"],
# "status": "active",
# "created_at": "2024-03-15T10:30:00Z"
# }If you include a secret when creating the webhook, store it securely. You can use it to verify webhook deliveries (recommended for production).
Payload Format
job.completed
{
"event": "job.completed",
"webhook_id": "wh_abc123",
"timestamp": "2024-03-15T10:35:00Z",
"data": {
"id": "job_xyz789",
"status": "completed",
"url": "/v1/transcriptions/job_xyz789"
}
}job.failed
{
"event": "job.failed",
"webhook_id": "wh_abc123",
"timestamp": "2024-03-15T10:35:00Z",
"data": {
"id": "job_xyz789",
"status": "failed",
"error": {
"type": "invalid_request_error",
"code": "invalid_audio_format",
"message": "The audio file could not be decoded."
},
"url": "/v1/transcriptions/job_xyz789"
}
}For the full transcription result (text, segments, timing, etc.), fetch the job using the ID:
curl -X GET "https://asr.lesan.ai/v1/transcriptions/job_xyz789" \
-H "Authorization: Bearer YOUR_API_KEY"Verifying Webhook Signatures
If you set a webhook secret, you can verify webhook deliveries using an HMAC-SHA256 signature of the raw request body. This helps ensure the request was not tampered with.
import hmac
import hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
WEBHOOK_SECRET = "whsec_abc123..." # From webhook creation
@app.route("/webhooks/lesan", methods=["POST"])
def handle_webhook():
# Verify the signature
signature = request.headers.get("X-Webhook-Signature") # Example header name
if signature:
expected = hmac.new(
WEBHOOK_SECRET.encode(),
request.data,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
return jsonify({"error": "Invalid signature"}), 401
# Process the event
payload = request.json
event = payload["event"]
data = payload["data"]
if event == "job.completed":
print(f"Job {data['id']} completed")
# Recommended: fetch the final job payload from /v1/transcriptions/{id} and persist it
elif event == "job.failed":
print(f"Job {data['id']} failed: {data['error']['message']}")
# Handle the failure (retry, notify, etc.)
return jsonify({"received": True}), 200Managing Webhooks
List Webhooks
curl "https://asr.lesan.ai/v1/webhooks" \
-H "Authorization: Bearer YOUR_API_KEY"Update a Webhook
curl -X PATCH "https://asr.lesan.ai/v1/webhooks/wh_abc123" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/lesan-v2",
"events": ["job.completed"]
}'Test a Webhook
Send a test event to verify your endpoint is working:
curl -X POST "https://asr.lesan.ai/v1/webhooks/wh_abc123/test" \
-H "Authorization: Bearer YOUR_API_KEY"Delete a Webhook
curl -X DELETE "https://asr.lesan.ai/v1/webhooks/wh_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"Delivery Tracking
Lesan AI tracks webhook delivery attempts. If your endpoint is unreachable or returns a non-2xx status code, we retry with exponential backoff:
- Retry schedule — 1 minute, 5 minutes, 30 minutes, 2 hours, 24 hours
- Max attempts — 5 retries per event
- Timeout — 10 seconds per delivery attempt
- Auto-disable — After 100 consecutive failures, the webhook is automatically disabled
Best Practices
- Always verify signatures — Never process unverified webhook payloads
- Respond quickly — Return a 200 status within 10 seconds. Process data asynchronously if needed
- Handle duplicates — Use the job
idto deduplicate events in case of retries - Use HTTPS — Webhook URLs must use HTTPS for security
- Store the secret securely — Treat the webhook secret like an API key
- Monitor delivery — Check the webhook delivery logs for failures
See the ASR guide for async transcription setup, or the Error Codes reference for understanding error payloads.