Skip to main content

Webhook Best Practices

Recommendations for building reliable webhook integrations.

Respond Quickly

Return a 2xx response within 30 seconds. Process events asynchronously:

@app.route('/webhooks/scribesight', methods=['POST'])
def webhook():
event = request.json

# Queue for background processing
task_queue.enqueue(process_event, event)

# Acknowledge immediately
return '', 200

Handle Duplicates

Events may be delivered more than once. Use the event ID for idempotency:

def process_event(event):
event_id = event['id']

# Check if already processed
if redis.sismember('processed_events', event_id):
return

# Process the event
handle_event(event)

# Mark as processed (with TTL)
redis.sadd('processed_events', event_id)
redis.expire('processed_events', 86400 * 7) # 7 days

Verify Signatures

Always verify the webhook signature before processing:

if not verify_signature(request.data, signature_header):
abort(401)

See Signature Verification for implementation details.

Handle All Event Types

Include a default handler for unknown events:

def handle_event(event):
event_type = event['event']

handlers = {
'transcription.completed': handle_transcription_completed,
'content_analysis.completed': handle_analysis_completed,
}

handler = handlers.get(event_type, handle_unknown_event)
handler(event)

def handle_unknown_event(event):
# Log and ignore unknown events
logger.info(f"Unknown event type: {event['event']}")

Use HTTPS

Webhook URLs must use HTTPS. We won't deliver to HTTP endpoints.

Monitor Deliveries

Check the webhook dashboard for delivery status:

  1. Go to Settings → Webhooks
  2. Click on your webhook endpoint
  3. View recent deliveries and any failures

You can also fetch deliveries via API:

curl https://scribesight.com/api/v1/webhooks/wh_xxx/deliveries \
-H "Authorization: Bearer sk_live_xxx"

Handle Failures Gracefully

If your endpoint is down:

  1. We'll retry with exponential backoff (up to 5 attempts)
  2. After exhausting retries, you'll receive a notification
  3. Events are stored for 30 days for replay

To replay missed events:

# Get the event from the deliveries log
curl https://scribesight.com/api/v1/webhooks/wh_xxx/deliveries \
-H "Authorization: Bearer sk_live_xxx"

# Manually trigger a test delivery
curl -X POST https://scribesight.com/api/v1/webhooks/wh_xxx/test \
-H "Authorization: Bearer sk_live_xxx"

Use Project Filtering

Only receive events from relevant projects:

curl -X POST https://scribesight.com/api/v1/webhooks \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhooks/scribesight",
"events": ["transcription.completed"],
"project_ids": ["proj_xxx", "proj_yyy"]
}'

Rotate Secrets Regularly

Rotate webhook secrets periodically:

curl -X POST https://scribesight.com/api/v1/webhooks/wh_xxx/rotate-secret \
-H "Authorization: Bearer sk_live_xxx"

The old secret remains valid for 24 hours during rotation.

Test Before Production

Use the test endpoint to verify your integration:

curl -X POST https://scribesight.com/api/v1/webhooks/wh_xxx/test \
-H "Authorization: Bearer sk_live_xxx"

This sends a webhook.test event to your endpoint.