Webhooks Guide

In a nutshell, webhooks are needed to handle responses from Veriff services about:

  • Events happening in the verification session

  • Verification session decisions

  • System’s confidence about the genuineness of a session

  • Data about different checks and extractions

  • Session info (e.g., session ID, attempt ID, different timestamps)

In order to use a webhook, you need to create an endpoint, i.e. a webhook URL on your side that accepts payloads posted by Veriff’s services.


Available webhook types

  • Decision webhook, used by most solutions and products, returns the result of the verification once the verification has been processed and contains info about the session

  • Event webhook, optional webhook, tracks the events happening in the identity verification process performed by the end-user

  • Watchlist screening webhook, returns data from the check performed in a AML Screening service verification session

  • INE webhook, returns data from the check performed in the Mexican Electoral Registry (INE) registry verification session

  • CURP webhook, returns data from the check performed in the Mexican Population Registry (CURP) registry verification session

  • INE+CURP webhook, returns data from the check performed in the Mexican Electoral Registry (INE) and Mexican Population Registry (CURP) verification session

  • User-defined statuses webhook, returns data from when the Customer Portal user defines a custom status for an attempt

  • Full Auto webhook, available only for Self Serve: Essential Plan integrations which return insights, extractions and decisionScore data


Which webhook type I need?

Veriff offers a number of solutions (aka products) to verify end-user’s identity, and uses different webhooks to pass back the verification data.

There is no single webhook that you always need to set up. The list of webhooks you need to configure depends on the product(s) you are using.

You need to configure the decision webhook to receive session decision and verified data from Veriff for:

Configuring the decision webhook for other products and solutions is optional, you may do it if you want to receive session info (e.g., session decision, attempt ID, decision timestamp).

For all the solutions, you can choose to configure the optional event webhook to notify you about the progress of the verification flow (events).

For specific Mexican registry checks Veriff sends:

Veriff sends the user-defined statuses webhook for when user has added a status to an attempt in the Veriff Customer Portal.

Veriff sends the full auto webhook for Self-Serve Essential Plan customers.


Webhook prerequisites

  1.  Make sure you have access to the Veriff Customer Portal
    1. If you do not, see the Getting Started → Sign up and Log in articles
  2. See the list of Which webhook type I need? and/or Available webhook types sections to understand which webhook(s) you may need
  3.  Set up webhook URL(s) on your side and have them at hand
    1.  Make sure they match the Webhook URL requirements
    2. Make sure your system is able to handle Webhooks receipt, delivery and resending requirements
  4. Secure your communication, check the HMAC Authentication and Endpoint Security article
  5. Make sure your system is able to handle the Backwards compatible changes

6.Proceed to Set up webhooks section below

Webhook delivery, receipt and resending

Order of delivery: to follow the best practices, Veriff does not guarantee that the webhooks are delivered in the order in which they are generated. Therefore, you should not expect to receive them in that order either, and should implement a logic to handle this accordingly.

Delivery approach: we guarantee the delivery of webhook at-least-once. The receiving API should be idempotent.

Confirmation of receipt: After sending the webhook, Veriff’s systems expect a confirmation about receiving the webhook from your side. This confirmation from your server should come within 5,000 ms, and we expect it to be in the form of a successful HTTP response code (a 200 code).

Rule of resending: If the confirmation does not arrive within that timeframe, for example there is a network connectivity issue or technical issue with delivering the notification (any non-200 response code), Veriff will try to resend the failed webhook for up to a week.

Webhook URL requirements

  • Only HTTPS URLs are allowed

  • Veriff does not allow adding custom ports to webhook URLs


Set up webhooks

Step 1: Configure webhook URL

  1. Go to the Veriff Customer Portal (you need to have an active account with Veriff)

  2. Navigate to All Integrations on the left navigation bar

  3. Find and open the relevant integration

  4. Navigate to the Settings tab on the integration's page

  5. Fill in the relevant webhook URL input field with the URL where your endpoint is accepting payloads from Veriff

Note that the image below does not contain all the possible webhook URLs. The list available depends on your integration.

Settings page showing webhook decisions URL and callback URL for integration configuration.

Step 2: Tie the verification result to the end-user

When your server receives a response from Veriff, you need to be able to reference it to the relevant end-user.

You can do this by using the Veriff session ID or by using your own end-user identifier.

Using the Veriff' session ID

To track this, record the Veriff session ID value during session creation. It can be found in the session response payload as verification.id

Some webhook’s payloads refer to it as either session ID or attempt ID, or both. Please see the specific webhook payload for exact info.

Using your own end-user ID

You need to provide this to Veriff.

You can store the end-user identifier in the vendorData or endUserId property during the session creation.

Note: it is technically possible for one end-user to be associated with multiple verification sessions. Therefore, if you are only recognizing end-users by your own identifier, and not Veriff's session ID, this could potentially create ambiguous situations in code.

Step 3: Secure the webhook communication

It is important to check that the webhook responses do indeed originate from Veriff. All the activities are picked up by a webhook listener, which need to be secured.

For that we use the X-HMAC-SIGNATURE header, which value is an HMAC-SHA256 hex encoded keyed hash using your shared secret key.

There are three ways to secure the webhook listener:

  • Have a secure TLS server for your webhook listener (Veriff will call only HTTPS URLs which are hosted by servers with a publicly verifiable certificate)

  • Verify the X-AUTH-CLIENT and X-HMAC-SIGNATURE headers on the received webhooks (the signature is calculated using the shared secret key that only you and Veriff know)

  • Allowlist the Veriff IP range for webhook listeners (ask your Solutions Engineer for info)

→ See the HMAC Authentication and Endpoint Security section about how you can create and validate the X-HMAC-SIGNATURE

Step 4: Test webhooks

Do not use sensitive data or expose personally identifiable information (PII) even when testing.

Webhooks testing prerequisites

  • Active integration with Veriff

  • Webhook URL is defined in Veriff Customer Portal

  • Basic understanding of HTTP/HTTPS protocols

  • (Optional) Development environment for local testing

Webhooks testing flow

We recommend using the decision webhook to test.

  1. Set up a webhook URL to receive Veriff data (see  Get webhook URL for testing)

  2. Add the webhook URL to the Webhook decision URL field in Veriff environment (see Configure webhook URL for info)

  3. Start a verification session (see your options in the Create verification session article)

  4. Open the session URL on your device and go through the verification flow

  5. Update session status to approved or declined in the Veriff Environment (see Forcing the status and data of the verification session when testing[↗] in the Knowledge Base (requires a login to the Veriff environment))

  6. Check your webhook listener for webhook data

Get webhook URL for testing

If you do not have an existing webhook URL to test with, then depending on if you are going to use PII data or not, see the options below:

  • Use a free service when testing without PII data

  • Set up a local webhook listener

Testing without PII data

If you are not going to use PII data, use free Webhook.site[↗] service, where you can create a unique URL.

After you have generated the URL, go through steps 2-5 in the flow above. Then, check the page on the Webhook.site to see the data sent via the webhook.

Testing using PII data

If PII data is going to be used then it is recommended that you create a server for your webhook listener. Below you find:

  • A sample JS script to set up a server to listen for POST requests at /hook and log incoming JSON data

  • Guide to using ngrok to get a publicly accessible URL, allowing external services to send data to your local server for webhook testing and debugging

Install dependencies

First, make sure you have express and body-parser installed:

npm install express body-parser

Create the server script

Use the following javascript code to set up a simple Express server to receive webhook data.

onst express = require("express")
const bodyParser = require("body-parser")

const app = express()
const PORT = 3000

app.use(bodyParser.json())

app.listen(PORT, () => console.log(`🚀 Server running on port ${PORT}`))

app.use(bodyParser.json())

app.post("/hook", (req, res) => {
  console.log(req.body) 
  res.status(200).end() 
})

Run the server

Save this code to a file (e.g., server.js) and start the server by running:

node server.js

You should see a message in the terminal confirming that the server is running on localhost:3000: Server running on port 3000

Expose the server to the internet using ngrok

To test webhooks or allow external services to send data to your local server, you need to make localhost:3000 accessible from the internet. Let us use ngrok.

  1. Install ngrok (if you have not already) by following the instructions on ngrok's website[↗].

  2. In a new terminal window, run the command bash ngrok http 3000 to start a tunnel to localhost:3000

  3. Ngrok will display output similar to this: Forwarding https://1234abcd.ngrok.io -> http://localhost:3000 This public URL (https://1234abcd.ngrok.io) is now a tunnel to your local server

Test webhooks with the ngrok URL

Paste the ngrok URL (e.g., https://1234abcd.ngrok.io/hook) to the Webhook decision URL in Veriff Customer Portal.

Go through the steps 2-5 above in the flow.

When the webhook sends data, it will reach your local /hook endpoint, and you will see the request data logged in the terminal where your server is running.

Mock payload and shared secret key for local testing

You can use the example signature and sample payload below to test webhooks sending and receipt and not depend on Veriff sending the response. Use the curl command below.

Mock shared secret key for testing

To validate this example signature and payload, use a shared secret key abcdef12-abcd-abcd-abcd-abcdef012345. Otherwise you will see an authentication error that the API key and shared secret key do not match.

Beware the hardspaces: generating the value may vary depending on the programming language used, e.g., some languages include the hard spaces in the body, and some omit them.

curl --request POST 'https://your.url'\
--header 'accept: application/json' \
--header 'x-auth-client: 8e4f7cd8-7a19-4d7d-971f-a076407ee03c' \
--header 'x-hmac-signature: 01fa3ded011bfce75672c99877a6cc1cf7aeaeda0ccb6b43fc21b60f595063c2' \
--header 'content-type: application/json' \
--data '{
  "status": "success",
  "verification": {
    "id": "12df6045-3846-3e45-946a-14fa6136d78b",
    "code": 9001,
    "person": {
      "gender": null,
      "idNumber": null,
      "lastName": "MORGAN",
      "addresses": [
        {
          "fullAddress": "1234 Snowy Ridge Road, Indiana, 56789 USA",
          "parsedAddress": {
            "city": null,
            "unit": null,
            "state": "Indiana",
            "street": "1234 Snowy Ridge Road",
            "country": "USA",
            "postcode": "56789",
            "houseNumber": "null"
          }
        }
      ],
      "firstName": "SARAH",
      "citizenship": null,
      "dateOfBirth": "1967-03-30",
      "nationality": null,
      "yearOfBirth": "1967",
      "placeOfBirth": "MADRID",
      "pepSanctionMatch": null
    },
    "reason": null,
    "status": "approved",
    "comments": [],
    "document": {
      "type": "DRIVERS_LICENSE",
      "number": "MORGA753116SM9IJ",
      "country": "GB",
      "validFrom": null,
      "validUntil": "2022-04-20",
      "placeOfIssue": "MADRID",
      "firstIssue": "2015-03-21",
      "issueNumber": "01",
      "issuedBy": "ISSUER"
    },
    "reasonCode": null,
    "vendorData": "12345678",
    "decisionTime": "2019-11-06T07:18:36.916Z",
    "acceptanceTime": "2019-11-06T07:15:27.000Z",
    "additionalVerifiedData": {
      "driversLicenseCategory": {
        "B": true
      },
      "driversLicenseCategoryFrom": {
        "B": "2019-10-06"
      },
      "driversLicenseCategoryUntil": {
        "B": "2025-10-05"
      },
      "estimatedAge": 32,
      "estimatedGender": 0.613
    },
    "riskLabels": [
      {
        "label": "document_integration_level_crosslinked_with_fraud",
        "category": "document",
        "sessionIds": [
          "5a2358e7-fd31-4fcb-a23f-4d76651ba68a"
        ]
      },
      {
        "label": "document_integration_level_crosslinked_with_multiple_declines",
        "category": "document",
        "sessionIds": [
          "fd5c1563-1d23-4b1a-ae46-7ba429927ed8"
        ]
      }
    ],
    "biometricAuthentication": {
      "matchedSessionId": "d40edb60-6ae6-4475-be72-84b81669cce6",
      "matchedSessionVendorData": "User001"
    }
  },
  "technicalData": {
    "ip": "186.153.67.122"
  }
}'


Checklist to verify production readiness

Basic setup

  • Webhook endpoint is properly configured in the Veriff Customer Portal

  • Endpoint is accessible via HTTPS

  • Basic logging is implemented and verified

  • Test webhooks have been successfully received and processed

  • Your setup is compatible with Veriff’s Backwards compatible changes

Security essentials

  • Webhook signature validation is implemented

  • Secrets are stored securely (not in code)

  • IP allowlist is configured (if needed)

  • PII data handling requirements are met

Core implementation

  • Webhook processing is asynchronous

  • System handles out-of-order webhook delivery correctly

  • Idempotency checks are implemented (handling at-least-once delivery)

  • Response time is consistently under 5000ms

  • Server returns HTTP 200 status code upon successful receipt

  • System can handle webhook retries for up to one week

  • Basic error handling is in place

Testing & validation

  • All webhook types have been tested

  • Error scenarios have been verified

  • Payload structure is validated

  • Success/failure rates are monitored

Monitoring

  • Basic alerts are set up for failures (see Codes section for overview of possible different error codes)

  • Webhook delivery is tracked

  • Error logs are reviewed

  • Response times are monitored


Article versioning

Date

Description

Mar 31, 2025

Links to IDV products’ guides updated

Mentions of “Full Auto” removed

Mentions of “Self-Serve: Essential Plan” updated

Mar 12, 2025

Documentation published