Skip to main content
Webhooks allow you to receive real-time HTTP notifications when events occur in your KYC workflows. Instead of polling the API for updates, webhooks push data to your server automatically.

How Webhooks Work

  1. Event Occurs: A user completes a session, a document is processed, or a status changes
  2. Event Published: The event is published to our internal message queue
  3. Webhook Delivered: Your configured endpoint receives a signed HTTP POST request
  4. Acknowledgment: Your server responds with 2xx to confirm receipt

Webhook Categories

Webhook Security

All webhooks are signed using HMAC-SHA256 to ensure authenticity. See Signature Verification for implementation details.

Security Headers

Every webhook request includes:
HeaderDescription
X-Webhook-IDUnique event ID for idempotency (evt_abc123...)
X-Webhook-TimestampUnix timestamp when event was created
X-Webhook-SignatureHMAC-SHA256 signature (sha256=...)
User-AgentKYC-Webhooks/1.0
Content-Typeapplication/json

Configuration

Configure webhooks in your tenant settings via the API or dashboard:
curl -X PATCH https://kyc.legaltalent.ai/kyc/tenants/me/notification-channels \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "webhook_url": "https://your-server.com/webhooks/kyc",
    "notification_emails": ["alerts@yourcompany.com"]
  }'
When you set a webhook_url without providing a webhook_secret, a secure secret is automatically generated for you. The secret is returned masked in API responses (e.g., ****************************a1b2).

Webhook Envelope

All webhooks share a common envelope structure:
{
  "id": "evt_abc123def456",
  "type": "kyc.session.processed",
  "created": 1735228800,
  "data": {
    // Event-specific payload
  }
}
FieldTypeDescription
idstringUnique event ID - use for idempotency
typestringEvent type (e.g., kyc.session.processed)
createdintegerUnix timestamp of event creation
dataobjectEvent-specific payload

Best Practices

Return a 2xx response within 10 seconds. Process webhook data asynchronously if needed.
@app.post("/webhooks/kyc")
async def handle_webhook(request: Request, background_tasks: BackgroundTasks):
    payload = await request.json()
    
    # Acknowledge immediately
    background_tasks.add_task(process_webhook, payload)
    return {"received": True}
Use the X-Webhook-ID header to deduplicate events. Store processed event IDs to avoid reprocessing.
def handle_webhook(event_id: str, payload: dict):
    if redis.sismember("processed_events", event_id):
        return  # Already processed
    
    # Process the event
    process_event(payload)
    
    # Mark as processed (with TTL for cleanup)
    redis.sadd("processed_events", event_id)
    redis.expire("processed_events", 86400 * 7)  # 7 days
Always verify the webhook signature before processing. See Signature Verification.
Webhooks may be retried if your server doesn’t respond with 2xx. Design your handlers to be idempotent.
Always use HTTPS endpoints for production webhooks. HTTP endpoints are only allowed in development.

Retry Policy

If your endpoint fails to respond with 2xx, the webhook will not be automatically retried. Ensure your endpoint is reliable and responds quickly.
For critical workflows, we recommend:
  • Monitoring your webhook endpoint uptime
  • Using a queue-based architecture for processing
  • Implementing fallback polling for missed events

Testing Webhooks

Local Development

Use tools like ngrok to expose your local server:
ngrok http 3000
# Use the generated URL as your webhook_url

Webhook Testing Endpoint

You can use the staging environment to test webhooks without affecting production data.

Notification Channels

In addition to webhooks, you can configure:
ChannelDescription
WebhookHTTP POST to your endpoint with signed payloads
EmailEmail notifications to configured addresses
SlackRich notifications to Slack channels via webhook
Configure multiple channels in your tenant settings:
{
  "webhook_url": "https://your-server.com/webhooks/kyc",
  "webhook_secret": "whsec_...",
  "notification_emails": ["alerts@company.com", "compliance@company.com"],
  "slack_webhook_url": "https://hooks.slack.com/services/..."
}

Next Steps