Skip to main content

Webhooks

Webhooks are used to asynchronously notify your system about events such as onboarding progress, pending requirements, or entitlement status changes. This allows you to react to updates without the need for constant polling.

Overview

  • Protocol: HTTPS POST requests sent to your registered URL.
  • Security: Payloads are signed using the Ed25519 algorithm. You must verify the signature to ensure authenticity.
  • Retry Policy: If your server returns a non-200 status (e.g., 5xx), the system will retry delivery with exponential backoff.
  • Idempotency: Each event has a unique id and timestamp. Always return HTTP 200 OK to acknowledge receipt.

Managing Webhooks

Register a Webhook

Endpoint: POST /webhooks

When registering a webhook, you can now specify exactly which events should be delivered to that URL.

Request Parameters:

FieldTypeRequiredDescription
urlStringYesHTTPS endpoint where notifications will be delivered.
include_all_eventsBooleanNo(Default true) If true, the webhook subscribes to all current and future event types, and event_types list is ignored.
event_typesList[String]NoA specific list of event types to subscribe to.
Ignored if include_all_events is true.
View Example Request
curl -X POST https://<kyc_domain>/api/v1/webhooks \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://client.example.com/dlt-webhook",
"include_all_events": false,
"event_types": [
"requirementsQuestionnaire",
"entitlementCompleted"
]
}'
View Example Response
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"key_id": "string",
"url": "https://client.example.com/dlt-webhook",
"event_types": [
"requirementsQuestionnaire",
"entitlementCompleted"
],
"include_all_events": false,
"public_key": "aH92jD8kL9n2Z4V3x...",
"created_at": "2025-12-05T14:22:30.497Z"
}
Important

Store the public_key returned in the registration response. You will need it to verify the signatures of incoming webhook requests.

List Registered Webhooks

Endpoint: GET /webhooks

Retrieves a paginated list of all registered webhooks and their configurations.

View Example Response
{
"items": [
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"key_id": "string",
"url": "https://client.example.com/dlt-webhook",
"event_types": [
"requirementsQuestionnaire"
],
"include_all_events": true,
"public_key": "aH92jD8kL9n2Z4V3x...",
"created_at": "2025-12-05T14:22:30.500Z"
}
],
"total": 1,
"page": 1,
"size": 50,
"pages": 1
}

Delete a Webhook

Endpoint: DELETE /webhooks/{webhook_id}


Handling Events

Payload Format

Each webhook is an HTTPS POST request containing a JSON payload and a signature header.

Header:

X-DLT-Signature: dupyAbK5Z2vB7cNHN5pu7voGKPANyjyM/g...==
Content-Type: application/json

Body:

{
"id": "8e9b9a45-6212-4a77-bb43-4b8d123a5e42",
"owner_id": "8e9b9a45-6212-4a77-bb43-4b8d123a5e42",
"owner_type": "person",
"entitlement_trigger_id": "8e9b9a45-6212-4a77-bb43-4b8d123a5e42",
"entitlement_id": "9a9b9a45-6212-4a77-bb43-4b8d123a5e42",
"timestamp": "2024-10-29T12:15:42Z",
"type": "requirementsQuestionnaire",
"details": {
// Event specific data
}
}

Common Event Types

TypeDescription
requirementsQuestionnaireTriggered when a user needs to answer additional questions.
requirementsVidTriggered when a video identification step is required.
entitlementCompletedTriggered when a workflow (like KYC) finishes successfully.
entitlementFailedTriggered when a workflow is rejected or fails.

Verifying Signatures

To ensure message integrity and authenticity, the system signs each webhook payload using its private Ed25519 key. You must verify this using the public_key you received during registration.

Verification Steps:

  1. Read the raw request body (exact bytes, do not parse as JSON yet).
  2. Retrieve the signature from the X-DLT-Signature header.
  3. Use an Ed25519 library to verify the signature against the body bytes.

Python Example

import nacl.signing  # requires 'pynacl' library
import nacl.encoding

# 1. Get these from your config/headers
public_key_hex = "aH92jD8kL9n2Z4V3x..." # From registration response
signature_hex = request.headers.get("X-DLT-Signature")
payload_bytes = request.data # Raw body bytes

# 2. Setup verification key
verify_key = nacl.signing.VerifyKey(public_key_hex, encoder=nacl.encoding.Base64Encoder)

# 3. Verify
try:
verify_key.verify(payload_bytes, bytes.fromhex(signature_hex))
print("✅ Signature valid")
except:
print("❌ Invalid signature")
# Return 400 or 401