Webhooks

To properly receive incoming webhooks, your server should provide an endpoint supporting:
- POST requests are either raw in text/plain if encrypted or application/json if no secret was set
You can use a service like e.g. https://webhook.site/ to test receiving webhooks from your developer dashboard.
Our webhook service supports two events, which describe the status of a flow. Those are:
- ticket.verification.in_progress: your flow has completed a number of steps (subprocesses) and is waiting for user's intervention to continue to next steps or to retry previous failed one.
- ticket.verification.completed: your flow has completed its processing. It has been either
ACCEPTED
orREJECTED
.
The ticket.verification.in_progress event is triggered when a Verification has completed a number of steps (subprocesses) and it's waiting for user-intervention to continue if it's appropriate. Notification payload specifies a set of properties as shown on following JSON. It will contain its ticket, so it can be tracked by your processes. Also, it holds its event, and its sub_event, which will be explained later. The property flow_status determines ticket's current state. The value of the disposition property can either be
PASSED
, FAILED
or RETRY
, which determines last executed subprocess' state. It also specifies how many attempts can be done on property remaining_attempts if disposition has been set as RETRY
. Property data contains suprocesses results, which we'll take a look afterwards.{
"ticket": "762ebbda-0edb-4e48-86bc-11a280273601",
"event": "ticket.verification.in_progress",
"sub_event": "verification.liveness",
"flow_status": "IN_PROGRESS",
"disposition": "PASSED",
"remaining_attempts": 3,
"data": { ... }
}
PASSED:
all subprocesses were executed correctly and their results have been considered as OK.RETRY
: this status is set when an exception has been raised, or any subprocess' result has been considered as unacceptable and has retries to attempt, eg. liveness detection process.FAILED
, this status is set when an exception has been raised, or any subprocess' result has been considered as unacceptable and no more retries can be atempted, eg. liveness detection process.
In this property, we will receive one of both values:
verification.liveness
and verification.id_proofing
This subevent is triggered when biometrical subprocesses were executed, which consist of
Facial analysis
and Liveness detection
. In this subevent, property data contains biometrical subprocesses' results. An example is shown bellow:{
"ticket": "762ebbda-0edb-4e48-86bc-11a280273601",
"event": "ticket.verification.in_progress",
"sub_event": "verification.liveness",
"flow_status": "IN_PROGRESS",
"disposition": "PASSED",
"remaining_attempts": 3,
"data": {
"facial_analysis": {
"status": true,
"confidence_score": "100",
"age_range": "22-30"
},
"liveness_detection": {
"status": true,
"validation_messages": [
"Liveness detected"
]
}
}
}
This subevent is triggered when Identity verification subprocesses were executed, which consist of
Document detection
, Id proofing
and Photo matching
. In this subevent, property data contains identity verification subprocesses' results. An example is shown bellow:{
"ticket": "762ebbda-0edb-4e48-86bc-11a280273601",
"event": "ticket.verification.in_progress",
"sub_event": "verification.id_proofing",
"flow_status": "IN_PROGRESS",
"disposition": "PASSED",
"remaining_attempts": 3,
"data": {
"document_detection": {
"status": true
},
"id_proofing": {
"status": true,
"validations": {
"recognized_document_type": "VALID",
"image_quality": "VALID",
"document_expiry": "VALID",
"mrz": "VALID",
"rfid": "NON_VALIDATED_OR_ABSENT",
"readability": "VALID",
"security": "VALID",
"general_status": "VALID",
"barcode": "VALID",
"authenticity": "NON_VALIDATED_OR_ABSENT",
"minimum_required_fields_read": "VALID"
}
},
"photo_matching": {
"status": true,
"similarity_score": "99.94"
}
}
}
The ticket.verification.completed event is triggered when a Verification has completed all of its subprocesses, or an error has been raised and there are no more retries to attempt. Notification payload specifies a set of properties as shown on following JSON. It will contain its ticket, so it can be tracked by your processes. Also, it holds its event. The flow_status specified ticket's current state, which can be either
ACCEPTED
or REJECTED
, this value depends on confidence_score property. The value of the disposition property can be either PASSED
or FAILED
which determines last executed subprocess' state. It also gives final results of entire flow, such as risk_code and confidence_score.{
"ticket": "762ebbda-0edb-4e48-86bc-11a280273601",
"event": "ticket.verification.completed",,
"flow_status": "ACCEPTED",
"disposition": "PASSED",
"remaining_attempts": 3,
"risk_code": "LOW",
"confidence_score": 99.99
}
ACCEPTED
: all flow's subprocesses were executed correctly and confidence_score has got toACCEPTED
scoring threshold.REJECTED
: this status is set when an exception has been raised, or any subprocess' result has been considered as unacceptable and no more retries can be atempted and confidence_score has got toREJECTED
scoring threshold.
PASSED:
all flow's subprocesses were executed correctly and their results have been considered as OK, so ticket is set to COMPLETED state.FAILED
, this status is set when an exception has been raised, or any subprocess' result has been considered as unacceptable and no more retries can be atempted, eg. liveness detection process.
Here you find a further description of the response values below, it represents both event responses as these share the same response structure:
Key | Data type | Description |
---|---|---|
ticket | string | The UUID of the Identity Verification which triggered this webhook. This will help you query our backend API for the details of the Identity Verification. |
event | string | The type of event that triggered this webhook. |
flow_status | string | This holds the result of the processed ticket and its confidence_score threshold matching.
As noted above, its value may be one of these 2 posibilities:
- ACCEPTED
- REJECTED |
disposition | string | This holds the result of the last executed subprocess.
As noted above, its value may be one of these 2 posibilities:
- PASSED
- FAILED |
remaining_attempts | number | Specifies the number of remaining retries that could be attempted. |
risk_code | string | This contains risk analysis based on 3 possible values listed below, in order from safest to riskiest evaluation result:
- LOW
- MODERATE
- HIGH
This value depends on confidence_score result |
confidence_score | number | This value is the calculation result from all factors and subprocesses, going from 0 to 100. Used for ticket's acceptance or rejection. |
Webhooks are a crucial node to ensure the functionality of your integration, as such, they can be the target of a malicious user aiming to disrupt the service. In order to protect your application from these threats, you must include a 32 bytes-long secret in your webhook configuration, which will be used to encrypt the request body.
When you enable Encryption, the Webhook event is sent as text/plain. Below you'll find an example of how to decipher an incoming webhook request. We assume both variables
response_headers
and response_body
are present in the response you received via the webhook. The cipher initialization vector will be sent over as a 16 bytes metadata (header) of the response.Javascript
const crypto = require("crypto")
// Your response headers from the webhook.
const response_headers = {}
// Your response body from the webhook.
const response_body = ""
// In the example here it is already a string.
const encrypted_result = Buffer.from(response_body, 'base64')
const iv = Buffer.from(response_headers['x-pvt-cipher-iv'], 'base64')
const cipher = crypto.createDecipheriv('aes-256-cbc', "YOUR_WEBHOOK_SECRET", iv)
const decrypted_result_bytes = Buffer.concat([cipher.update(encrypted_result), cipher.final()])
const decrypted_result = decrypted_result_bytes.toString()
const json_result = JSON.parse(decrypted_result)
Last modified 24d ago