Webhooks
Receive real-time notifications about events in your unboarder account.
Overview
Webhooks allow your application to receive real-time HTTP notifications when specific events occur in your Onboarder account. Instead of polling the API, webhooks push data to your server as events happen. Configure your webhook endpoints in the unboarder dashboard, then implement handlers to process the events.
- Real-time event notifications
- HMAC-SHA256 signature verification for security
- Automatic retry with exponential backoff
- Flexible event filtering with wildcard support
Setting Up Webhooks
- Go to your unboarder dashboard at dashboard.onboarder.com
- Navigate to Developers → Webhooks
- Click "Add Endpoint" and enter your webhook URL (must be HTTPS)
- Select the events you want to receive (e.g., verification.*, form.*)
- Save and copy your webhook secret - you'll need this to verify signatures
- Implement the webhook handler on your server using the examples below
Webhook Events
Subscribe to specific events or use wildcards to receive all events in a category.
| Event | Description |
|---|---|
| verification.* | All verification events |
| verification.completed | KYC verification completed successfully |
| verification.failed | KYC verification failed |
| verification.pending | KYC verification is pending review |
| verification.created | New verification session created (API-Only/SDK pattern) |
| verification.submitted | Verification submitted for processing (API-Only/SDK pattern) |
| verification.expired | Verification session expired without submission |
| country.blocked | User attempted verification from blocked country |
| fraud.detected | Potential fraudulent verification detected |
| reverification.required | User needs to re-verify (expired or updated requirements) |
| biometric.* | All biometric enrollment and verification events |
| biometric.enrollment.completed | User completed biometric enrollment (face and/or voice) |
| biometric.verification.passed | Biometric verification passed (transaction authorization) |
| biometric.verification.failed | Biometric verification failed (fraud attempt or poor quality) |
| transaction.authorized | User authorized a transaction with biometric authentication |
| user.created | New user account created |
| consent.granted | User granted OAuth consent to access their data |
| consent.revoked | User revoked OAuth consent |
Webhook Payload
When an event occurs, unboarder sends an HTTP POST request to your webhook URL with the following structure:
{ "id": "evt_5RtY9xMp6qKLn3N8Q1", "type": "verification.completed", "created": "2024-01-15T10:30:00Z", "data": { "object": { "id": "ver_2NxZ8wKN5pPQj4L7M9", "userId": "user_abc123", "type": "nin", "status": "verified", "result": { "verified": true, "confidence": 0.98, "data": { "firstName": "John", "lastName": "Doe", "dateOfBirth": "1990-01-15", "documentNumber": "12345678901" } }, "createdAt": "2024-01-15T10:25:00Z", "completedAt": "2024-01-15T10:30:00Z" } }}Implementing Webhook Handlers
unboarder signs all webhook requests with HMAC-SHA256. Always verify the signature to ensure the request came from unboarder and hasn't been tampered with.
Signature Headers
- X-unboarder-Signature: The signature hash
- X-unboarder-Timestamp: Unix timestamp of when the signature was created
Webhook Handler Implementation
const crypto = require('crypto');const express = require('express');const app = express();
function verifyWebhookSignature(payload, signature, secret, timestamp) { // Prevent replay attacks (optional but recommended) const tolerance = 300; // 5 minutes const currentTime = Math.floor(Date.now() / 1000); if (Math.abs(currentTime - timestamp) > tolerance) { throw new Error('Webhook timestamp is too old'); }
// Create signature const signedPayload = `${timestamp}.${JSON.stringify(payload)}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex');
// Compare signatures return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) );}
// Express.js endpoint exampleapp.post('/webhooks/unboarder', express.raw({type: 'application/json'}), (req, res) => { const signature = req.headers['x-unboarder-signature']; const timestamp = req.headers['x-unboarder-timestamp']; const secret = process.env.WEBHOOK_SECRET;
try { const payload = JSON.parse(req.body); const isValid = verifyWebhookSignature(payload, signature, secret, timestamp);
if (!isValid) { return res.status(401).json({ error: 'Invalid signature' }); }
// Process the webhook based on event type switch (payload.type) { case 'verification.completed': console.log('Verification completed:', payload.data.object.id); // Update your database, send notifications, etc. break; case 'verification.failed': console.log('Verification failed:', payload.data.object.id); break; case 'form.submission.created': console.log('New form submission:', payload.data.object.id); break; default: console.log('Unhandled event type:', payload.type); }
res.status(200).json({ received: true }); } catch (error) { console.error('Webhook error:', error); res.status(400).json({ error: 'Webhook processing failed' }); }});
app.listen(3000, () => console.log('Webhook server running on port 3000'));Retry Behavior
If your endpoint returns a non-2xx status code or times out, unboarder will retry the webhook with exponential backoff:
- Attempt 1: Immediately
- Attempt 2: 5 minutes later
- Attempt 3: 15 minutes later
- Attempt 4: 1 hour later
- Attempt 5: 6 hours later
After 5 failed attempts, the webhook delivery is marked as failed. You can view failed deliveries and retry them manually from your dashboard.
Best Practices
- Always verify webhook signatures to ensure requests are from unboarder
- Respond with 2xx status code quickly (within 10 seconds), then process the webhook asynchronously
- Implement idempotency - handle duplicate events gracefully using the event ID
- Use HTTPS endpoints only for security
- Monitor your webhook endpoint health and failure rates in the dashboard
- Rotate webhook secrets periodically for enhanced security
- Store event IDs in your database to prevent duplicate processing
Testing Webhooks
To test your webhook integration:
- Use the "Send Test Event" button in your dashboard to send sample webhook events
- Use tools likengrok to expose your local development server
- Check the webhook logs in your dashboard to see delivery status and responses
- Verify that your handler correctly processes different event types
- Test signature verification by intentionally sending invalid signatures