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

json
{
  "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

json
{
  "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:

bash
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}), 200

Managing Webhooks

List Webhooks

bash
curl "https://asr.lesan.ai/v1/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY"

Update a Webhook

bash
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:

bash
curl -X POST "https://asr.lesan.ai/v1/webhooks/wh_abc123/test" \
  -H "Authorization: Bearer YOUR_API_KEY"

Delete a Webhook

bash
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 id to 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.