--- title: "Webhooks Guide | Veriff.com" slug: "webhooks-guide" description: "Main guide to setting up webhooks for different verification types, how-to of webhooks testing, and info about webhooks headers and payload." tags: ["Webhooks"] status: "update" updated: 2026-01-15T13:38:02Z published: 2026-01-15T13:38:02Z canonical: "devdocs.veriff.com/webhooks-guide" --- > ## Documentation Index > Fetch the complete documentation index at: https://devdocs.veriff.com/llms.txt > Use this file to discover all available pages before exploring further. # 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) > [!NOTE] > 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](/v1/docs/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](/v1/docs/event-webhook), optional webhook, tracks the events happening in the identity verification process performed by the end-user - [Watchlist screening webhook](/v1/docs/watchlist-screening-webhook), returns data from the check performed in a **AML Screening** service verification session - [INE webhook](/v1/docs/ine-webhook), returns data from the check performed in the **Mexican Electoral Registry (INE)** registry verification session - [CURP webhook](/v1/docs/curp-webhook), returns data from the check performed in the **Mexican Population Registry (CURP)** registry verification session - [INE+CURP webhook](/v1/docs/inecurp-webhook), returns data from the check performed in the **Mexican Electoral Registry (INE)** and **Mexican Population Registry (CURP)** verification session - [User-defined statuses webhook](/v1/docs/user-defined-statuses-webhook), returns data from when the Customer Portal user defines a custom status for an attempt - [Full Auto webhook](/v1/docs/full-auto-webhook), available only for [Self Serve: Essential Plan](/v1/docs/essential-plan-full-auto) 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. > [!NOTE] > 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. Decision webhookEvents webhookWatchlist-screening webhookMexican registiesUser-defined statuses webhookFull Auto webhook You need to configure the [decision webhook](/v1/docs/decision-webhook) to receive session decision and verified data from Veriff for: - [Document + selfie IDV](/v1/docs/document-selfie-idv) and [Document-only IDV](/v1/docs/document-only-idv) - [Biometric Authentication](/v1/docs/biometric-authentication) - [Biometric Liveness](/v1/docs/biometric-liveness) - [Age Estimation](/v1/docs/age-estimation) - [Proof of Address Extraction](/v1/docs/proof-of-address-extraction) - [AML screening](/v1/docs/aml-screening) via IDV integration - [UK DIATF](/v1/docs/uk-diatf) - [Mexican INE Biometric Database Verification](/v1/docs/ine-biometric-database-verification) - [Indian Aadhaar Database Verification](/v1/docs/aadhaar-database-verification-check) 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](/v1/docs/event-webhook) to notify you about the progress of the verification flow (events). Veriff sends the [watch-list screening webhook](/v1/docs/watchlist-screening-webhook) for [AML screening](/v1/docs/aml-screening) For specific Mexican registry checks Veriff sends: - [INE webhook](/v1/docs/ine-webhook) - [CURP webhook](/v1/docs/curp-webhook) - [Combined INE+CURP webhook](/v1/docs/inecurp-webhook) Veriff sends the [user-defined statuses webhook](/v1/docs/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](/v1/docs/full-auto-webhook) for Self-Serve [Essential Plan](/v1/docs/essential-plan-full-auto) 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](https://devdocs.veriff.com/docs/signing-up) and [Log in](https://devdocs.veriff.com/docs/logging-in) articles 2. See the list of [Which webhook type I need?](https://devdocs.veriff.com/docs/webhooks-guide#which-webhook-type-i-need) and/or [Available webhook types](https://devdocs.veriff.com/docs/webhooks-guide#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](https://devdocs.veriff.com/docs/webhooks-guide#webhook-url-requirements) requirements 2. Make sure your system is **able to handle** [Webhooks receipt, delivery and resending](https://devdocs.veriff.com/docs/webhooks-guide#webhook-delivery-receipt-and-resending) requirements 4. Secure your communication, check the [HMAC Authentication and Endpoint Security](https://devdocs.veriff.com/docs/hmac-authentication-and-endpoint-security) article 5. Make sure your system is **able to handle** the [Backwards compatible changes](https://devdocs.veriff.com/docs/backwards-compatible-changes) 6.Proceed to [Set up webhooks](/v1/docs/webhooks-guide#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 --- ## Webhook’s headers and payload ### Headers When you receive webhooks from Veriff, you will see the following headers: | Header name | Description | | --- | --- | | `x-auth-client` | A mandatory header field, required to identify the request sender. Its value is your integration’s API key | | `x-hmac-signature` | A mandatory header field, required to authenticate the request sender. Generated by signing the webhook’s raw request body with your integration’s shared secret key (see [here](https://devdocs.veriff.com/docs/hmac-authentication-and-endpoint-security#validate-webhooks-xhmacsignature-header-value) for troubleshooting guide) | Example: ```Custom {  "x-auth-client": "b8f42d1e-3a7c-4e9f-a2b5-d8c6f1a4e7b3",  "x-hmac-signature": "d4c7a8f1e5b2c9d6f3a8e1b4c7d9f2a5e8b3c6d1f4a7e9b2c5d8f1a6e3b7c4d9",  "vrf-integration-id": "f6a8b2c4-d7e1-4f3a-b9c2-e5d8f1a6b3c7" } ``` ### Payload The contents of a webhook payload depend on the webhook type you are using. The contents have been separately detailed in each webhook’s documentation, in “Sample request” and “Request properties explained” sections. --- ## 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.](https://cdn.document360.io/5c26138b-b1e9-404e-a2e4-c83a49245be7/Images/Documentation/Webhooks_Set Webhook URL.jpg) ### 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` > [!NOTE] > 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](https://devdocs.veriff.com/docs/hmac-authentication-and-endpoint-security) section about how you can* ***create and validate the X-HMAC-SIGNATURE*** ### Step 4: Test webhooks #### Webhooks testing prerequisites - Active test integration with Veriff - Webhook URL is defined in Veriff Customer Portal - Basic understanding of HTTP/HTTPS protocols - (Recommended) Development environment for local testing if you do not yet have a webhook service set up #### Webhooks testing flow We recommend using the decision webhook to test. 1. Set up a local webhook listener to get a webhook URL 2. Add the webhook URL to the Webhook decision URL field in Veriff environment (see [Configure webhook URL](/v1/docs/webhooks-guide#step-1-configure-webhook-url) for info) 3. Start a verification session (see your options in the [Create verification session](/v1/docs/how-to-generate-sessions-manually) 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](https://help.veriff.com/en/articles/3492920-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 Be mindful of the personally identifiable information you may be sending during testing! #### Set up local webhook listener *Note that the testing guide below has been created with the help of LLM.* 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: ```javascript 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. ```javascript const 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: ```plaintext 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](https://ngrok.com/download)[↗]. 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](/v1/docs/webhooks-guide#webhooks-testing-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 decision webhook sending and receipt and not depend on Veriff sending the response. Use the `curl` command below. > [!NOTE] > **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 hardspace**s: 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 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](/v1/docs/backwards-compatible-changes) ### Security essentials - [ ] Webhook signature validation is implemented - [ ] Secrets are stored securely (not in code) - [ ] [IP allowlist](/v1/docs/allowlisted-urls-and-ip-addresses) 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](/v1/docs/codes) section for overview of possible different error codes) - [ ] Webhook delivery is tracked - [ ] Error logs are reviewed - [ ] Response times are monitored --- ## Changelog | Date | Description | | --- | --- | | Jan 15, 2026 | `vfr-integration-id` removed from [Headers](/v1/docs/webhooks-guide#headers) section | | Sep 5, 2025 | - Note about flexible API keys feature removed - [Webhook headers](/v1/docs/webhooks-guide#webhooks-headers-and-payload) section moved before [Set up webhooks](/v1/docs/webhooks-guide#set-up-webhooks) section | | Sep 3, 2025 | Link to `x-hmac-signature` header validation guide added to the list in [Headers](/v1/docs/webhooks-guide#headers) section | | Jul 11, 2025 | [Webhooks headers and payload](/v1/docs/webhooks-guide#webhooks-headers-and-payload) section added | | Jul 10, 2025 | ["Test webhooks"](/v1/docs/webhooks-guide#step-4-test-webhooks) section updated, remarks about testing without PII data removed | | Jun 6, 2025 | Heading “Article versioning” changed to “Changelog” | | May 7, 2025 | In the **Mock payload and shared secret key for local testing** section, it is now specified that it is decision webhook’s mock payload | | 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 | A session during which the end-user is verified. It starts when a session is created, it can contain several attempts (i.e. steps of uploading media, sending additional data etc.) and it ends when a conclusive decision (“approved”, “declined”, “expired”/”abandoned”) is granted. Each verification session receives an unique ID, aka the **session ID**, which can be added to the API URL when making API requests. This is returned after the end-user's data has been analysed and the system has reached a conclusion about the end-user's verification session. Can be `approved`, `declined`, `resubmission_requested`, `expired` or `abandoned`. Only if previously agreed with Veriff, you may also be receiving `review`. A **unique identifier of a verification session**. It is automatically created as soon as you create a session. In the **API requests' context**, one verification session comprises many steps (uploading data, uploading images, getting a decision, etc.). You can call several endpoints using the same **session ID**, to get all kinds of different data from that specific session. You can find its value in the **response payload** of your **POST /sessions API request**, in the `verification.id` parameter. An event-triggered API, meaning that rather than sending information or performing a function as a response to an application's request, it performs this when a certain trigger event happens. There are different types of webhooks, see *Technical Guides* > *Webhooks* > *Different webhook types* for more info. A webhook listener is an endpoint in a web application or service that waits for and receives HTTP requests from other web applications or services. It listens for incoming HTTP requests sent by other applications when certain events occur. The webhook listener parses a request sent by a source application at a certain trigger event, extracts the relevant data, and takes appropriate actions based on the content of the message. These actions are specific to the application or service. A **mandatory header** field in API requests, **required to authenticate the request sender**. Its value is a **HMAC-SHA256 hex encoded hashed value of the request payload** that has been **signed using a shared secret key** known to both the sending and receiving party. Each API requests documentation in the API Documentation specifies the payload to be encoded. For more info about the signature itself, see *Technical Guides* > *HMAC Authentication and Endpoint Security.* **Mandatory elements** in the **API requests**, containing the metadata. **Mandatory parameter for authentication**, used to **sign the payload to create the X-HMAC-SIGNATURE** for API requests. This is a **secret credential**. You can find it in **Veriff Customer Portal** > **Integration** tab (you need to be logged in). Occasionally, referred to as the "API private key" or the "Private key". Personally Identifiable Information ## Related - [Decision webhook](/decision-webhook.md) - [Event webhook](/event-webhook.md) - [Watchlist-screening webhook](/watchlist-screening-webhook.md) - [INE webhook](/ine-webhook.md) - [INE+CURP webhook](/inecurp-webhook.md) - [CURP webhook](/curp-webhook.md) - [User-defined statuses webhook](/user-defined-statuses-webhook.md) - [Full Auto webhook](/full-auto-webhook.md) - [Integrations](/how-to-create-an-integration.md) - [Create verification session](/how-to-generate-sessions-manually.md)