Webhook
Overview
- Webhook Notification provides a secure, signed, asynchronous event delivery mechanism for Identity Verification Solution.
- Webhook and
callbackUrlare mutually exclusive. To use signed Webhooks, configure your endpoint in ACMP and do not passcallbackUrlin API requests (Generate URL API, Document API, etc.). IfcallbackUrlis provided, notifications are sent to that URL instead; signed headers (aai-timestamp,aai-nonce,aai-signature) are not included. - All webhook requests are signed to ensure authenticity, integrity, and replay protection.
Webhook delivery is not guaranteed.
Clients must implement polling to retrieve final results if webhook delivery fails.
We recommend a polling interval of 10 minutes or greater.
Webhook Endpoint Requirements
Clients must provide an HTTPS endpoint capable of receiving webhook notifications.
Network & Security
- Only HTTPS endpoints are supported
HTTP endpoints are not allowed - Supported TLS versions:
- TLS 1.2 or higher
HTTP Request
| Item | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Timeout | 60 seconds |
Retry Policy
If a webhook request fails, the system retries delivery automatically.
Failure Conditions
- Network error
- Request timeout (> 60 seconds)
- Any non-2xx HTTP response
Retry Schedule
| Attempt | Delay |
|---|---|
| 1st retry | 5 seconds |
| 2nd retry | 10 seconds |
| 3rd retry | 20 seconds |
Webhooks follow an at-least-once delivery model. Clients must handle duplicate events safely.
Webhook Configuration
Webhook configuration can be managed in ACMP.
- Webhook HTTPS URL
- Customer / Account information
- Shared secret key (secretKey) for request signing
The secret key displayed in ACMP is Base64-encoded. Decode it before use.
Content Signature
All webhook requests are signed using a shared secret.
Supported Signature Algorithms
- HMAC-SHA256
- HMAC-SHA512
Signature Headers
| Header | Description |
|---|---|
| aai-timestamp | Request timestamp (seconds, Unix epoch) |
| aai-nonce | One-time random string |
| aai-signature | Base64-encoded signature |
What to sign
The exact raw HTTP POST body (UTF-8), as received. Read or cache it before your framework parses JSON. Do not hand-build JSON or re-serialize after parsing (JSON.stringify, toJSONString, etc.) — any formatting change breaks the signature.
How to sign (HMAC-SHA256)
keyBytes = Base64.decode(sharedSecretFromConsole)
signature = Base64( HMAC_SHA256(keyBytes, rawRequestBody) )
aai-timestamp and aai-nonce are for replay checks only — not part of the HMAC input.
For HMAC-SHA512, use the algorithm configured for your webhook in ACMP.
Common pitfalls
- Using the ACMP secret string directly as the HMAC key → decode Base64 first
- Re-serializing JSON for signing → use the raw body bytes
- Passing
callbackUrlin API calls but expectingaai-signature→ use ACMP Webhook only (see Overview)
Signature Verification (Client Side)
Clients must verify webhook requests before processing.
Step 1: Read Headers
timestamp = aai-timestamp
nonce = aai-nonce
signature = aai-signature
Step 2: Validate Timestamp
- The timestamp must be within ±5 minutes of current time
- Requests outside this window must be rejected
Step 3: Validate Nonce
- Each nonce must be unique
- Recommended: cache nonce values for 5 minutes
- If the nonce is reused, reject the request
Step 4: Recalculate signature
Apply the formula above (keyBytes + rawRequestBody). Compare the result to the aai-signature header.
Java example
// requestBody = raw HTTP body; secretKey = shared secret from ACMP (Base64, as shown)
public static boolean verify(String requestBody, String secretKey, String signatureHeader)
throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(secretKey);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(keyBytes, "HmacSHA256"));
String expected = Base64.getEncoder().encodeToString(
mac.doFinal(requestBody.getBytes(StandardCharsets.UTF_8)));
return expected.equals(signatureHeader);
}Step 5: Compare Signatures
- If signatures do not match → reject with HTTP 400 / 401
Step 6: Respond
| Response | Result |
|---|---|
| Any 2xx | Delivery successful |
| Non-2xx | Delivery failed, retry will be triggered |
Event Format
Event Example
{
"eventId": "uuid",
"eventType": "COMPLETED",
"webhookId": "wh_xxx",
"data": {
"signatureId": "1234567890"
}
}Verify using the raw HTTP body you received; do not copy this example into code.
{
"eventId": "uuid",
"eventType": "BUSINESS_VERIFICATION_STATUS",
"data": {
"id": "KYBC-201464826803499999",
"status": "COMPLETED",
"checkItem": "Basic Business Verification",
"updatedAt": 1769405823
}
}{
"eventId": "uuid",
"eventType": "AML_OGS_UPDATE",
"data": {
"profileId": "PF_R5BoIxxxxxxxxxxQnnNVqi",
"caseId": 1998600000000026050,
"alertId": 2001680000000082882,
"numberOfNewResults": 0,
"numberOfUpdatedResults": 1
}
}{
"eventId":"uuid",
"eventType":"KYB_IDV_EMAIL",
"data": {
"email":"[email protected]",
"directUrl":"",
"expireHour": 24,
"emailType":"REQUEST_IDV, NOTIFY_IDV_SUCCESS, NOTIFY_IDV_FAILED"
}
}{
"eventId":"uuid",
"eventType":"KYB_QNRE_EMAIL",
"data": {
"email":"[email protected]",
"otpCode":"",
"url": "",
"emailType":"OTP_VERIFICATION, FORM_NOTIFICATION, SUBMISSION_CONFIRMATION"
}
}Event Fields
| Field | Description |
|---|---|
| eventId | Unique event identifier |
| eventType | Event type |
| webhookId | Webhook configuration ID in ACMP |
| data | Event payload |
Event Types
| eventType | Description |
|---|---|
| COMPLETED | Full verification process completed |
| SUBMIT_COMPLETED | Data submission completed |
| BUSINESS_VERIFICATION_STATUS | Business verification status (triggers on change) |
| AML_OGS_UPDATE | This event notifies about ongoing screening updates. |
| OCR_COMPLETED | Triggered when OCR processing is fully completed, providing the extracted document data for real-time access. |
| CASE_MANUAL_CORRECTED | Triggered after a case has been manually reviewed and corrected by an agent, syncing the final verified result. |
| KYB_IDV_EMAIL | Triggered when an IDV (Identity Verification) email needs to be sent during the KYB process, providing email details for custom delivery handling. |
| KYB_QNRE_EMAIL | Triggered when a questionnaire-related email needs to be sent, including OTP verification codes, form notification links, or submission confirmations. |
