Webhooks
Webhooks allow you to receive real-time HTTP notifications when events occur in your Biometry account. Instead of polling the API, webhooks push data to your server as soon as events happen.
Available Events
| Event | Description |
|---|---|
docauth.completed | Triggered when a document authentication check completes |
Webhook Management API
Create a Webhook
Configure a webhook endpoint to receive event notifications.
Authorization
This endpoint requires an API token as Bearer in the Authorization header. Go to Authorization guide for details.
Request
POST https://api.biometrysolutions.com/api-gateway/webhooksHeaders
- Authorization* - Your API Token.
Body Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
api_key_id | string | Yes | The API key ID to associate with this webhook |
url | string | Yes | The HTTPS endpoint URL to receive webhook events |
events | array | Yes | List of events to subscribe to (e.g., ["docauth.completed"]) |
headers | object | No | Custom headers to include with each webhook request |
Sample Request
curl --location 'https://api.biometrysolutions.com/api-gateway/webhooks' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc' \ --header 'Content-Type: application/json' \ --data '{ "api_key_id": "ak_abc123", "url": "https://your-server.com/webhooks/biometry", "events": ["docauth.completed"], "headers": { "X-Custom-Header": "my-value" } }'Response
{ "data": { "id": "wh_fe402c29-b543-4413-8624-af1a2a0b2f2c", "api_key_id": "ak_abc123", "project_id": "proj_xyz789", "url": "https://your-server.com/webhooks/biometry", "events": ["docauth.completed"], "status": "active", "headers": { "X-Custom-Header": "my-value" }, "retry_config": { "max_retries": 5, "initial_delay": 1000000000, "max_delay": 300000000000, "backoff_multiplier": 2 }, "success_count": 0, "failure_count": 0, "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z", "secret": "whsec_a1b2c3d4e5f6..." }, "message": "Webhook created successfully. Save the secret - it won't be shown again."}{ "message": "validation failed"}List Webhooks
Get all webhook configurations for your project.
Request
GET https://api.biometrysolutions.com/api-gateway/webhooksHeaders
- Authorization* - Your API Token.
Sample Request
curl --location 'https://api.biometrysolutions.com/api-gateway/webhooks' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc'Response
{ "data": [ { "id": "wh_fe402c29-b543-4413-8624-af1a2a0b2f2c", "api_key_id": "ak_abc123", "project_id": "proj_xyz789", "url": "https://your-server.com/webhooks/biometry", "events": ["docauth.completed"], "status": "active", "success_count": 142, "failure_count": 3, "last_delivered_at": "2024-01-15T14:22:00Z", "created_at": "2024-01-15T10:30:00Z", "updated_at": "2024-01-15T10:30:00Z" } ], "message": "Webhooks retrieved successfully"}Get Webhook
Retrieve a specific webhook configuration.
Request
GET https://api.biometrysolutions.com/api-gateway/webhooks/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook configuration ID |
Headers
- Authorization* - Your API Token.
Sample Request
curl --location 'https://api.biometrysolutions.com/api-gateway/webhooks/wh_fe402c29-b543-4413-8624-af1a2a0b2f2c' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc'Update Webhook
Update a webhook configuration.
Request
PATCH https://api.biometrysolutions.com/api-gateway/webhooks/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook configuration ID |
Headers
- Authorization* - Your API Token.
Body Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | New endpoint URL |
events | array | Updated list of events to subscribe to |
status | string | Webhook status: active or disabled |
headers | object | Custom headers to include |
Sample Request
curl --location --request PATCH 'https://api.biometrysolutions.com/api-gateway/webhooks/wh_fe402c29-b543-4413-8624-af1a2a0b2f2c' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc' \ --header 'Content-Type: application/json' \ --data '{ "status": "disabled" }'Delete Webhook
Delete a webhook configuration.
Request
DELETE https://api.biometrysolutions.com/api-gateway/webhooks/{id}Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook configuration ID |
Headers
- Authorization* - Your API Token.
Sample Request
curl --location --request DELETE 'https://api.biometrysolutions.com/api-gateway/webhooks/wh_fe402c29-b543-4413-8624-af1a2a0b2f2c' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc'Response
Returns 204 No Content on success.
Rotate Secret
Generate a new HMAC secret for a webhook. Use this if your secret is compromised.
Request
POST https://api.biometrysolutions.com/api-gateway/webhooks/{id}/rotate-secretPath Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook configuration ID |
Headers
- Authorization* - Your API Token.
Sample Request
curl --location --request POST 'https://api.biometrysolutions.com/api-gateway/webhooks/wh_fe402c29-b543-4413-8624-af1a2a0b2f2c/rotate-secret' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc'Response
{ "data": { "secret": "whsec_new_secret_value..." }, "message": "Secret rotated successfully. Save the new secret - it won't be shown again."}Get Delivery History
View the delivery history for a webhook.
Request
GET https://api.biometrysolutions.com/api-gateway/webhooks/{id}/deliveriesPath Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook configuration ID |
Headers
- Authorization* - Your API Token.
Sample Request
curl --location 'https://api.biometrysolutions.com/api-gateway/webhooks/wh_fe402c29-b543-4413-8624-af1a2a0b2f2c/deliveries' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc'Response
{ "data": [ { "id": "del_abc123", "webhook_config_id": "wh_fe402c29-b543-4413-8624-af1a2a0b2f2c", "event": "docauth.completed", "status": "delivered", "attempt_count": 1, "created_at": "2024-01-15T14:22:00Z", "delivered_at": "2024-01-15T14:22:01Z" }, { "id": "del_xyz789", "webhook_config_id": "wh_fe402c29-b543-4413-8624-af1a2a0b2f2c", "event": "docauth.completed", "status": "failed", "attempt_count": 3, "last_error": "HTTP 500", "last_status_code": 500, "next_retry_at": "2024-01-15T14:30:00Z", "created_at": "2024-01-15T14:20:00Z" } ], "message": "Deliveries retrieved successfully"}Delivery Statuses
| Status | Description |
|---|---|
pending | Delivery is queued and waiting to be sent |
processing | Delivery is currently being sent |
delivered | Successfully delivered (received 2xx response) |
failed | Delivery failed, will retry according to retry config |
dead_letter | All retry attempts exhausted |
Retry Delivery
Manually retry a failed or dead-lettered delivery.
Request
POST https://api.biometrysolutions.com/api-gateway/webhooks/{id}/deliveries/{delivery_id}/retryPath Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The webhook configuration ID |
delivery_id | string | The delivery ID to retry |
Headers
- Authorization* - Your API Token.
Sample Request
curl --location --request POST 'https://api.biometrysolutions.com/api-gateway/webhooks/wh_fe402c29-b543-4413-8624-af1a2a0b2f2c/deliveries/del_xyz789/retry' \ --header 'Authorization: Bearer eyJhbGciO...ANYea8r2xOG-Urc'Response
Returns 202 Accepted with message “Delivery queued for retry”.
Webhook Payload
When an event occurs, we send an HTTP POST request to your configured URL with the following payload:
Headers
| Header | Description |
|---|---|
Content-Type | Always application/json |
X-Biometry-Signature | HMAC-SHA256 signature for verification |
X-Biometry-Timestamp | Unix timestamp when the webhook was sent |
X-Biometry-Delivery-ID | Unique identifier for this delivery attempt |
X-Biometry-Event | The event type (e.g., docauth.completed) |
Payload Structure
{ "id": "del_abc123", "event": "docauth.completed", "timestamp": "2024-01-15T14:22:00Z", "api_version": "v1", "data": { "request_id": "fc5605c5-1234-5678-87cc-979cd72564d4", "session_id": "sess_fe402c29-b543-4413-8624-af1a2a0b2f2c", "result": "pass", "docauth_info": { "document_type": "National Identification Card", "country_code": "KGZ", "nationality_code": "KGZ", "nationality_name": "KYRGYZSTANI", "sex": "MALE", "first_name": "JOHN", "father_name": "CERA", "last_name": "DOE", "expiry_date": "2028-08-03", "document_number": "ID0833333", "birth_date": "2002-04-01", "current_result": "Passed" }, "processed_at": "2024-01-15T14:21:59Z", "scores_applied": false }}Payload Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique delivery ID |
event | string | Event type that triggered this webhook |
timestamp | string | ISO 8601 timestamp when the event occurred |
api_version | string | API version (currently v1) |
data.request_id | string | Original DocAuth request ID |
data.session_id | string | Session ID if provided in the original request |
data.result | string | Overall result: pass or fail |
data.docauth_info | object | Document authentication details (same as DocAuth API response) |
data.processed_at | string | When the document was processed |
data.scores_applied | boolean | Whether scoring rules were applied |
Signature Verification
To ensure webhook requests are genuinely from Biometry, verify the signature included in the X-Biometry-Signature header.
How Signatures Work
- We create a signed message:
{timestamp}.{payload} - We compute HMAC-SHA256 using your webhook secret
- The signature is sent as:
v1={hex_signature}
Verification Steps
- Extract the timestamp from
X-Biometry-Timestampheader - Concatenate:
{timestamp}.{raw_request_body} - Compute HMAC-SHA256 with your webhook secret
- Compare with the signature in
X-Biometry-Signatureheader
Node.js Example
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, timestamp, secret) { // Create the signed message const message = `${timestamp}.${payload}`;
// Compute expected signature const expectedSignature = 'v1=' + crypto .createHmac('sha256', secret) .update(message) .digest('hex');
// Use timing-safe comparison return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) );}
// Express.js exampleapp.post('/webhooks/biometry', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-biometry-signature']; const timestamp = req.headers['x-biometry-timestamp']; const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature, timestamp, process.env.WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); }
// Process the webhook const event = JSON.parse(payload); console.log('Received event:', event.event);
res.status(200).send('OK');});Retry Behavior
If your endpoint returns a non-2xx status code or times out, we automatically retry delivery with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 second |
| 3 | 2 seconds |
| 4 | 4 seconds |
| 5 | 8 seconds (max 5 minutes) |
After 5 failed attempts, the delivery is moved to the dead letter queue. You can manually retry dead-lettered deliveries via the API.
Timeout
Your endpoint must respond within 30 seconds. Requests that exceed this timeout are treated as failures and will be retried.
Best Practices
-
Respond quickly - Return a 2xx status immediately, then process the webhook asynchronously. Long-running processing should happen in a background job.
-
Handle duplicates - In rare cases, you may receive the same webhook more than once. Use the
idfield to deduplicate. -
Verify signatures - Always validate the
X-Biometry-Signatureheader to ensure requests are from Biometry. -
Use HTTPS - Webhook URLs must use HTTPS to ensure data is encrypted in transit.
-
Monitor deliveries - Check the delivery history regularly to catch and address any failures.
-
Rotate secrets periodically - Use the rotate-secret endpoint to generate new secrets as part of your security practices.