--- title: "Presence Verification" slug: "presence-verification" description: "Veriff Presence Verification confirms live human presence without ID documents, using selfie video and device signals, with optional Coercion Detection." updated: 2026-10-13T09:39:39Z published: 2026-10-13T09:39:39Z canonical: "devdocs.veriff.com/presence-verification" --- > ## 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. # Presence Verification | Available via API | Available via SDK | Needs configuration on Veriff's side | Needs a separate integration | Needs a solution-specific webhook | | --- | --- | --- | --- | --- | | ❌ | ✅ | ✅ | ✅ | ❌ | Presence Verification helps confirm that a real, live, single human is present in the verification session and is completing it on their own. It uses a passive selfie video and device signals captured by Veriff's native SDKs to help keep bots, deepfakes, injected media, and sessions guided by a third party out of your sign-up and high-risk flows, without asking the end-user for an identity document. Presence Verification is available in two tiers: - **Presence Verification**: assesses presence, uniqueness, and liveness from the selfie image and the full selfie video, together with device and network integrity signals. - **Presence Verification with Coercion Detection**: includes everything above, and also analyses the session audio and video to flag signs that a third party is guiding the end-user during the session. Presence Verification is available via native SDKs (iOS and Android) and web flow. Because the checks rely on the media and device signals that Veriff's SDK captures, Veriff strongly recommends using the solution via native SDKs. You need a separate integration for this solution, meaning existing solution's integrations cannot be used. Presence Verification is used as a standalone solution on that integration. All session-related **info is returned** **via** the decision webhook and can be **polled from different API endpoints**. The results of the verification can also be viewed in the Veriff Customer Portal, on the session's page. Contact your **solutions engineer** for info and configuration. --- ## Prerequisites - You have an [integration set up](/v1/docs/how-to-create-an-integration) with Veriff - **Presence Verification is configured** for that integration **by your Solutions Engineer**, including which tier you use - You have configured the [decision webhook](/v1/docs/decision-webhook) to get responses from Veriff (see the how-to in webhooks' [Set up webhooks](/v1/docs/webhooks-guide#set-up-webhooks) section) - You have integrated a Veriff native SDK (iOS or Android), and your app can request camera access from the end-user, and microphone access if you use Presence Verification with Coercion Detection - Your backend is ready to create sessions with [POST /sessions](https://devdocs.veriff.com/apidocs/v1sessions) using the API keys of your Presence Verification integration - Veriff **strongly recommends** that you **create and send** us the endUserId or vendorData - To use Presence Verification with Coercion Detection, the end-user must be 18 years or older. Presence Verification without Coercion Detection has no age requirement. *→ For more info about how to integrate using Android or iOS SDKs, see the* [*SDK Guides*](/v1/docs/sdk-guide) *section.* ### Key terminology | Term | Description | | --- | --- | | Injection attack | Feeding pre-recorded, synthetic, or manipulated media into the session instead of a live camera feed | | Liveness | Assessment of whether the face in the capture belongs to a live person rather than a photo, screen, mask, or deepfake | | Multiple parties present | A second person is visible in the session video | | Passive capture | The end-user records a short selfie video without performing gestures or prompted actions | | Presence Verification | Veriff solution that helps confirm that a real, live, single human is present and is completing the session on their own | | Presence Verification with Coercion Detection | Higher tier that also analyses the session audio and video for signs of third-party guidance | | Third-party guidance | Another person instructing, dictating to, or pressuring the end-user during the session, on or off camera | --- ## Flow overview ### Captured media During the session, Veriff's SDK accesses the selfie image, the selfie video, device metadata, and sensor data. No identity document is captured. ### Use via SDKs 1. Generate a verification session using the API keys and the `baseURL` of your Presence Verification integration (see the [API Documentation and API Reference](https://devdocs.veriff.com/apidocs) how to find these) ```bash curl -X POST \  --url '/v1/sessions/' \  -H 'X-AUTH-CLIENT: your-api-key' \  -H 'Content-Type: application/json' \  -d '{    "verification": {      "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",      "vendorData": "12345678"    }  }' ``` **Session creation json example** ```json {  "verification": {    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",    "vendorData": "12345678"  } } ``` - Veriff strongly recommends you create and send the `endUserId` or `vendorData` **Session creation bash example** 2. Capture the end-user's selfie video with Veriff's native SDK - Launch the Veriff iOS or Android SDK in your app. You need the session URL generated in step 1 (found in response payload as `verification.url`). - The end-user grants camera access, and microphone access if you use Presence Verification with Coercion Detection - The end-user records a short, passive selfie video 3. Session will be submitted automatically once the end-user completes the capture 4. Receive the results from Veriff via the decision webhook or poll them via [GET /sessions/{sessionId}/decision](/v1-api/apidocs/v1sessionsiddecision-1) endpoint - If the decision is `resubmission_requested`, the end-user sees a retry prompt in the session, records the video again, and Veriff sends a new decision #### Session lifecycle flow diagram ***Click to open SDK session lifecycle diagram*** Your backend creates a session, your app opens it in the Veriff SDK, the end-user records a passive selfie video, the SDK submits the session, and Veriff sends the decision webhook to your backend. If the decision is `resubmission_requested`, the end-user retries in the session and Veriff sends a new decision. Your backend can also poll the decision endpoint. ```mermaid sequenceDiagram    participant EU as End-user    participant App as Your app    participant BE as Your backend    participant API as Veriff API    participant SDK as Veriff SDK    BE->>API: POST /v1/sessions (endUserId, vendorData)    API-->>BE: Session URL (verification.url)    BE->>App: Session URL    App->>SDK: Launch SDK with session URL    SDK->>EU: Request camera and microphone access    EU->>SDK: Record passive selfie video    SDK->>API: Submit session automatically    Note over API: Automated processing    API-->>BE: Decision webhook    opt Decision is resubmission_requested        SDK->>EU: Retry prompt in the session        EU->>SDK: Record passive selfie video again        SDK->>API: Submit session automatically        API-->>BE: Decision webhook    end    opt Webhook not received        BE->>API: GET /v1/sessions/sessionId/decision        API-->>BE: Decision    end ``` ```plaintext sequenceDiagram    participant EU as End-user    participant App as Your app    participant BE as Your backend    participant API as Veriff API    participant SDK as Veriff SDK    BE->>API: POST /v1/sessions (endUserId, vendorData)    API-->>BE: Session URL (verification.url)    BE->>App: Session URL    App->>SDK: Launch SDK with session URL    SDK->>EU: Request camera and microphone access    EU->>SDK: Record passive selfie video    SDK->>API: Submit session automatically    Note over API: Automated processing    API-->>BE: Decision webhook    opt Decision is resubmission_requested        SDK->>EU: Retry prompt in the session        EU->>SDK: Record passive selfie video again        SDK->>API: Submit session automatically        API-->>BE: Decision webhook    end    opt Webhook not received        BE->>API: GET /v1/sessions/sessionId/decision        API-->>BE: Decision    end ``` --- ## Find decision and/or session related info You can get the data from three sources: - Receive the decision webhook (full example with placeholder values [below](/v1/docs/presence-verification#webhook-payload)) - Query the results via [GET /sessions/{sessionId}/decision](/v1-api/apidocs/v1sessionsiddecision-1) (payload is identical to the webhook) - View the session in the **Veriff Customer Portal** ### Solution-specific parameters Presence Verification does not add a solution-specific object to the payload. The result is returned in the standard decision fields: `verification.status` and `verification.code` show the outcome, and for sessions that are not approved, `verification.reason` and `verification.reasonCode` show why. Which reason codes you can receive depends on your configuration, for example whether you use Presence Verification with Coercion Detection and whether bot and velocity protection is enabled. See [Status and reason codes](/docs/presence-verification#status-and-reason-codes) below. #### Note about object and field visibility All objects and fields listed in the payload examples below are **mandatory** and always present. - `verification.person` and `verification.document` are always returned, but every field in them is `null`, because Presence Verification does not use an identity document - `verification.additionalVerifiedData` is returned as an empty object `{}` - `verification.reason` and `verification.reasonCode` are `null` when the session is `approved` - `verification.vendorData` and `verification.endUserId` are `null` if you did not send them - `technicalData.ip` can be `null` #### Note on session outcomes An `approved` session is identified by a `verification.status` of `approved`. It means the selfie and video appear genuine, a live end-user was present, and no signs of manipulation, non-uniqueness, or, on Presence Verification with Coercion Detection, third-party guidance were detected. A session can also end as: - `declined`: the inputs appear not genuine, the end-user does not appear to be present, a second person or third-party guidance was detected, or other fraudulent behaviour was detected - `resubmission_requested`: expected input is missing or of poor quality, for example the face is missing or not clearly visible, or the video is missing. The third-party guidance check never leads to `resubmission_requested`. - `expired` or `abandoned`: standard meanings, as for any other session #### Note on the decision fields For an approved session: - `verification.status` is `approved`, - `verification.code` is `9001`, and - `verification.reason` and `verification.reasonCode` are `null`. For a declined Presence Verification with Coercion Detection session, for example: - `verification.status` is `declined`, - `verification.code` is `9102`, - `verification.reason` is "Signs of third-party guidance during the session", and - `verification.reasonCode` is `589`. ### Webhook payload The example below uses **placeholder data** to show all **mandatory parameters and possible Presence Verification fields**. While mandatory fields are always present, solution-specific keys are omitted if a feature is disabled or data extraction fails. **Depending on your integration's configuration**, your **production payload may contain additional parameters**. For other parameters you might see, check the [decision webhook](/v1/docs/decision-webhook) documentation. #### Sample request **Approved session** ```json {  "status": "success",  "verification": {    "id": "12df6045-3846-3e45-946a-14fa6136d78b",    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",    "vendorData": "12345678",    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",    "status": "approved",    "code": 9001,    "reason": null,    "reasonCode": null,    "decisionTime": "2026-10-05T12:55:01.232Z",    "acceptanceTime": "2026-10-05T12:53:36.916Z",    "submissionTime": "2026-10-05T12:54:15.736755Z",    "person": {      "firstName": null,      "lastName": null,      "dateOfBirth": null,      "gender": null,      "nationality": null,      "idNumber": null,      "yearOfBirth": null,      "placeOfBirth": null,      "pepSanctionMatch": null,      "citizenship": null    },    "document": {      "number": null,      "type": null,      "country": null,      "state": null,      "validFrom": null,      "validUntil": null    },    "additionalVerifiedData": {},    "comments": []  },  "technicalData": {    "ip": "192.0.2.10"  } } ``` **Declined session** ```json {  "status": "success",  "verification": {    "id": "33bb5a12-7c84-4e2a-9f3d-2b1c6a9d4e57",    "attemptId": "5fa21d88-6e32-4f71-9ac4-8d3b7c5e2f10",    "vendorData": "87654321",    "endUserId": null,    "status": "declined",    "code": 9102,    "reason": "Signs of third-party guidance during the session",    "reasonCode": 589,    "decisionTime": "2026-10-05T09:12:44.512Z",    "acceptanceTime": "2026-10-05T09:10:03.118Z",    "submissionTime": "2026-10-05T09:11:57.402551Z",    "person": {      "firstName": null,      "lastName": null,      "dateOfBirth": null,      "gender": null,      "nationality": null,      "idNumber": null,      "yearOfBirth": null,      "placeOfBirth": null,      "pepSanctionMatch": null,      "citizenship": null    },    "document": {      "number": null,      "type": null,      "country": null,      "state": null,      "validFrom": null,      "validUntil": null    },    "additionalVerifiedData": {},    "comments": []  },  "technicalData": {    "ip": "192.0.2.11"  } } ``` #### Request properties explained - `status`: `string` Status of the response - `verification`: `object` Verification request decision object. `null` if decision is not available yet. - `id`: `string` UUID v4 which identifies the verification session - `attemptId`: `string` UUID v4 of the attempt which received a status (as shown in `verification.status` field) - `vendorData`: `string | null` The unique identifier that you created for your end-user. `null` if not specified. - `endUserId`: `string | null` The `UUID` that you created for your end-user. `null` if not specified. - `status`: `string` Verification status, one of `approved`, `declined`, `resubmission_requested`, `expired`, `abandoned` - `code`: `integer` Verification session decision code, one of `9001`, `9102`, `9103`, `9104`. For more info, see the [Verification session decision codes (table)](/v1/docs/verification-session-decision-codes-table). - `reason`: `string | null` Reason why the verification failed - `reasonCode`: `integer | null` Reason code of the failed verification. For more info, see the [Granular reason codes (table)](/v1/docs/granular-reason-codes). - `decisionTime`: `string | null` Timestamp of the decision, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601) - `acceptanceTime`: `string` Timestamp of the session generation, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601) - `submissionTime`: `string` Timestamp of when the session was submitted, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSSSSS+Timezone Offset` (ISO 8601) - `person`: `object` Data about the verified person. For Presence Verification, every field in this object is `null`. - `firstName`: `string | null` Person's first name as written on the document - `lastName`: `string | null` Person's last name as written on the document - `dateOfBirth`: `string | null` Person's date of birth, represented as `YYYY-MM-DD` - `gender`: `string | null` Person's gender, represented as M, F or X, or `null` if not present - `nationality`: `string | null` Person's nationality, represented as ISO 3166 `alpha-2` or `alpha-3` number - `idNumber`: `string | null` National identification number - `yearOfBirth`: `string | null` Person's year of birth, represented as `YYYY` - `placeOfBirth`: `string | null` Person's place of birth - `pepSanctionMatch`: `string | null` *Legacy field, may return incorrect result, should be ignored* - `citizenship`: `null` *Deprecated, always returns null* - `document`: `object` Verified document. For Presence Verification, every field in this object is `null`. - `number`: `string | null` Document number, `[a-zA-Z0-9]` characters only - `type`: `string | null` Document type, one of `PASSPORT`, `ID_CARD`, `RESIDENCE_PERMIT`, `DRIVERS_LICENSE`, `VISA`, `OTHER` - `country`: `string | null` Document issuing country, represented as ISO 3166 `alpha-2` code - `state`: `string | null` Document issuing state, represented as ISO 3166 `alpha-2` or `alpha-3` code - `validFrom`: `string | null` Document is valid from date - `validUntil`: `string | null` Document is valid until date - `additionalVerifiedData`: `object` Data that has been optionally verified for the session. Empty `{}` for Presence Verification. - `comments`: `array` *(Deprecated) Always returns empty []* - `technicalData`: `object` Technical data object - `ip`: `string | null` IP of the device from which the verification was made ### API call The example below uses **placeholder data** to show all **mandatory parameters and possible Presence Verification fields**. While mandatory fields are always present, solution-specific keys are omitted if a feature is disabled or data extraction fails. **Depending on your integration's configuration**, your **production payload may contain additional parameters**. For other parameters you might see, check the [GET /sessions/{sessionId}/decision](/v1-api/apidocs/v1sessionsiddecision-1) documentation. ***Click to open GET /decision response payload and field explanations*** **Approved session** ```json {  "status": "success",  "verification": {    "id": "12df6045-3846-3e45-946a-14fa6136d78b",    "attemptId": "00bca969-b53a-4fad-b065-874d41a7b2b8",    "vendorData": "12345678",    "endUserId": "a1b2c35d-e8f7-6d5e-3cd2-a1b2c35db3d4",    "status": "approved",    "code": 9001,    "reason": null,    "reasonCode": null,    "decisionTime": "2026-10-05T12:55:01.232Z",    "acceptanceTime": "2026-10-05T12:53:36.916Z",    "submissionTime": "2026-10-05T12:54:15.736755Z",    "person": {      "firstName": null,      "lastName": null,      "dateOfBirth": null,      "gender": null,      "nationality": null,      "idNumber": null,      "yearOfBirth": null,      "placeOfBirth": null,      "pepSanctionMatch": null,      "citizenship": null    },    "document": {      "number": null,      "type": null,      "country": null,      "state": null,      "validFrom": null,      "validUntil": null    },    "additionalVerifiedData": {},    "comments": []  },  "technicalData": {    "ip": "192.0.2.10"  } } ``` **Declined session** ```json {  "status": "success",  "verification": {    "id": "33bb5a12-7c84-4e2a-9f3d-2b1c6a9d4e57",    "attemptId": "5fa21d88-6e32-4f71-9ac4-8d3b7c5e2f10",    "vendorData": "87654321",    "endUserId": null,    "status": "declined",    "code": 9102,    "reason": "Signs of third-party guidance during the session",    "reasonCode": 589,    "decisionTime": "2026-10-05T09:12:44.512Z",    "acceptanceTime": "2026-10-05T09:10:03.118Z",    "submissionTime": "2026-10-05T09:11:57.402551Z",    "person": {      "firstName": null,      "lastName": null,      "dateOfBirth": null,      "gender": null,      "nationality": null,      "idNumber": null,      "yearOfBirth": null,      "placeOfBirth": null,      "pepSanctionMatch": null,      "citizenship": null    },    "document": {      "number": null,      "type": null,      "country": null,      "state": null,      "validFrom": null,      "validUntil": null    },    "additionalVerifiedData": {},    "comments": []  },  "technicalData": {    "ip": "192.0.2.11"  } } ``` **Response properties explained** - `status`: `string` Status of the response - `verification`: `object` Verification request decision object. `null` if decision is not available yet. - `id`: `string` UUID v4 which identifies the verification session - `attemptId`: `string` UUID v4 of the attempt which received a status (as shown in `verification.status` field) - `vendorData`: `string | null` The unique identifier that you created for your end-user. `null` if not specified. - `endUserId`: `string | null` The `UUID` that you created for your end-user. `null` if not specified. - `status`: `string` Verification status, one of `approved`, `declined`, `resubmission_requested`, `expired`, `abandoned` - `code`: `integer` Verification session decision code, one of `9001`, `9102`, `9103`, `9104`. For more info, see the [Verification session decision codes (table)](/v1/docs/verification-session-decision-codes-table). - `reason`: `string | null` Reason why the verification failed - `reasonCode`: `integer | null` Reason code of the failed verification. For more info, see the [Granular reason codes (table)](/v1/docs/granular-reason-codes). - `decisionTime`: `string | null` Timestamp of the decision, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601) - `acceptanceTime`: `string` Timestamp of the session generation, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSS+Timezone Offset` (ISO 8601) - `submissionTime`: `string` Timestamp of when the session was submitted, represented as `UTC YYYY-MM-DDTHH:MM:SS.SSSSSS+Timezone Offset` (ISO 8601) - `person`: `object` Data about the verified person. For Presence Verification, every field in this object is `null`. - `firstName`: `string | null` Person's first name as written on the document - `lastName`: `string | null` Person's last name as written on the document - `dateOfBirth`: `string | null` Person's date of birth, represented as `YYYY-MM-DD` - `gender`: `string | null` Person's gender, represented as M, F or X, or `null` if not present - `nationality`: `string | null` Person's nationality, represented as ISO 3166 `alpha-2` or `alpha-3` number - `idNumber`: `string | null` National identification number - `yearOfBirth`: `string | null` Person's year of birth, represented as `YYYY` - `placeOfBirth`: `string | null` Person's place of birth - `pepSanctionMatch`: `string | null` *Legacy field, may return incorrect result, should be ignored* - `citizenship`: `null` *Deprecated, always returns null* - `document`: `object` Verified document. For Presence Verification, every field in this object is `null`. - `number`: `string | null` Document number, `[a-zA-Z0-9]` characters only - `type`: `string | null` Document type, one of `PASSPORT`, `ID_CARD`, `RESIDENCE_PERMIT`, `DRIVERS_LICENSE`, `VISA`, `OTHER` - `country`: `string | null` Document issuing country, represented as ISO 3166 `alpha-2` code - `state`: `string | null` Document issuing state, represented as ISO 3166 `alpha-2` or `alpha-3` code - `validFrom`: `string | null` Document is valid from date - `validUntil`: `string | null` Document is valid until date - `additionalVerifiedData`: `object` Data that has been optionally verified for the session. Empty `{}` for Presence Verification. - `comments`: `array` *(Deprecated) Always returns empty []* - `technicalData`: `object` Technical data object - `ip`: `string | null` IP of the device from which the verification was made ### Veriff Customer Portal You can find the verification session related info, including the decision, in the Veriff Customer Portal, under the session's **Webhooks** tab. → *See* [*Review verification in Veriff Customer Portal*](/v1/docs/how-to-review-verification-in-veriff-customer-portal) *about how to view the session info in the Veriff Customer portal* --- ## Status and reason codes For an `approved` session, see: - `verification.code` about verification session decision code, one of `9001`, `9102`, `9103`, `9104` - `verification.status` about verification status, one of `approved`, `declined`, `resubmission_requested`, `expired`, `abandoned` If the Presence Verification session was `declined` or `resubmission_requested`, you can find additional information by checking: - `verification.reason` for the reason why the verification failed - `verification.reasonCode` for reason code of the failed verification and cross-reference it with [Granular reason codes (table)](/v1/docs/granular-reason-codes) | `verification.status` | `verification.reasonCode` | `verification.reason` | What does it mean? | | --- | --- | --- | --- | | `declined` | `589` | Signs of third-party guidance during the session | Signs were detected that another person guided the end-user during the session. Returned only with Presence Verification with Coercion Detection. | | `declined` | `502` | Multiple parties present in session | A second person was visible in the session video | | `declined` | `503` | Attempted deceit | The inputs appear not genuine | | `declined` | `519` | Attempted injection attack | Pre-recorded, synthetic, or manipulated media was fed into the session | | `declined` | `526` | Attempted deceit, photos streamed | Photos were streamed into the session instead of a live capture | | `declined` | `105` | Suspicious behaviour | Other fraudulent behaviour was detected | | `declined` | `109` | Velocity/abuse duplicated device | The device was already used in other sessions. Returned only if velocity protection is enabled. | | `declined` | `112` | Restricted IP location | The session came from a restricted IP location. Returned only if enabled for your integration. | | `resubmission_requested` | `603` | Video missing | The selfie video is missing. Ask the end-user to try again. | | `resubmission_requested` | `605` | Face image missing | The face image is missing. Ask the end-user to try again. | | `resubmission_requested` | `606` | Face is not clearly visible | The face is not clearly visible. Ask the end-user to try again in good lighting. | | `resubmission_requested` | `202` | Face not clearly visible | The face is not clearly visible. Ask the end-user to try again in good lighting. | | `resubmission_requested` | `656` | Multiple parties are present in the session | More than one face is present in the selfie. Ask the end-user to try again alone. | Depending on your configuration, you may also see other existing codes, for example `108` (duplicated end-user), `110` (duplicated ID), or `539` (resubmission limit exceeded). The table above aims to list the most common reasons why you may see the `decline` reason for a Presence Verification session. However, the session may be declined due to a reason that is not inherently Presence Verification related. In that case, to find info about the codes you are seeing, refer to: - [Verification session status codes (table)](/v1/docs/verification-session-status-codes-table) - [Verification session decision codes (table)](/v1/docs/verification-session-decision-codes-table) - [Granular reason codes (table)](/v1/docs/granular-reason-codes) --- ## Additional information ### Best practices **Use a native SDK**: Veriff strongly recommends the iOS and Android SDKs over the web flow, because the checks rely on the media and device signals the SDK captures. The API alone cannot run this solution; it only creates the session. **Camera and microphone access**: Make sure the end-user can grant camera access, and microphone access if you use Presence Verification with Coercion Detection, and explain in your app why they are needed. Without audio, the third-party guidance assessment cannot run. Adding Coercion Detection to an existing integration introduces a new runtime permission prompt and may require updating your app's privacy disclosures to cover audio capture. **Selfie image quality**: ensure that end-user's selfie image is of good quality. This will reduce the possibility of session going to `resubmission_requested`. **Send an** `endUserId` **or** `vendorData`: Create and send an `endUserId` or `vendorData` for every session. **Decision logic**: Drive your logic from `verification.code` and `verification.status`. Treat `verification.reasonCode` as an open set that can gain new values, and handle unknown codes gracefully. **Third-party guidance declines**: Treat `589` like other fraud-related declines in your risk handling. **Webhook first, polling as backup**: Use the decision webhook as the primary channel, and [GET /sessions/{sessionId}/decision](/v1-api/apidocs/v1sessionsiddecision-1) as a fallback. **Error handling**: Implement proper error handling for all possible validation results. **Webhook security**: Secure your webhook endpoint and verify request signatures **User experience**: Provide clear feedback to end-users about validation results **Ensure** [Backwards compatible changes](/v1/docs/backwards-compatible-changes) for webhooks and API connections ### FAQ #### How is Presence Verification different from IDV and Biometric Authentication? IDV answers "who is this person" using an identity document. Biometric Authentication answers "is this the same person as before" by matching against a previous session. Presence Verification uses no document and does no matching: it helps establish that a real person is present and acting on their own right now. #### Can I use Presence Verification via the API or the web flow? You cannot use the API alone: the API only creates the session. Web flow is supported, but Veriff strongly recommends native SDKs (iOS and Android) instead, because the checks rely on the media and device signals the SDK captures. #### Does the third-party guidance check ever request a resubmission? No. It results either in a pass or in a `declined` decision with reason code `589`. #### What happens if the end-user denies microphone access or there is no audio? #### The session is not declined for third-party guidance because audio is missing. #### Can I retrieve the media the end-user submitted? Yes, with the existing media endpoints: `GET /v1/sessions/{sessionId}/media`, `GET /v1/attempts/{attemptId}/media`, and `GET /v1/media/{mediaId}`. Data retention policies apply. #### Which languages does the audio assessment support? The audio assessment used in Presence Verification with Coercion Detection supports the following languages. | Language | Language | Language | Language | | --- | --- | --- | --- | | Afrikaans (af) | Albanian (sq) | Amharic (am) | Arabic (ar) | | Armenian (hy) | Assamese (as) | Azerbaijani (az) | Bashkir (ba) | | Basque (eu) | Belarusian (be) | Bengali (bn) | Bosnian (bs) | | Breton (br) | Bulgarian (bg) | Cantonese (yue) | Catalan (ca) | | Chinese (zh) | Croatian (hr) | Czech (cs) | Danish (da) | | Dutch (nl) | English (en) | Estonian (et) | Faroese (fo) | | Finnish (fi) | French (fr) | Galician (gl) | Georgian (ka) | | German (de) | Greek (el) | Gujarati (gu) | Haitian Creole (ht) | | Hausa (ha) | Hawaiian (haw) | Hebrew (he) | Hindi (hi) | | Hungarian (hu) | Icelandic (is) | Indonesian (id) | Italian (it) | | Japanese (ja) | Javanese (jw) | Kannada (kn) | Kazakh (kk) | | Khmer (km) | Korean (ko) | Lao (lo) | Latin (la) | | Latvian (lv) | Lingala (ln) | Lithuanian (lt) | Luxembourgish (lb) | | Macedonian (mk) | Malagasy (mg) | Malay (ms) | Malayalam (ml) | | Maltese (mt) | Maori (mi) | Marathi (mr) | Mongolian (mn) | | Myanmar (my) | Nepali (ne) | Norwegian (no) | Nynorsk (nn) | | Occitan (oc) | Pashto (ps) | Persian (fa) | Polish (pl) | | Portuguese (pt) | Punjabi (pa) | Romanian (ro) | Russian (ru) | | Sanskrit (sa) | Serbian (sr) | Shona (sn) | Sindhi (sd) | | Sinhala (si) | Slovak (sk) | Slovenian (sl) | Somali (so) | | Spanish (es) | Sundanese (su) | Swahili (sw) | Swedish (sv) | | Tagalog (tl) | Tajik (tg) | Tamil (ta) | Tatar (tt) | | Telugu (te) | Thai (th) | Tibetan (bo) | Turkish (tr) | | Turkmen (tk) | Ukrainian (uk) | Urdu (ur) | Uzbek (uz) | | Vietnamese (vi) | Welsh (cy) | Yiddish (yi) | Yoruba (yo) | --- ## Changelog | Date | Description | | --- | --- | | Oct 13, 2026 | Documentation published | Veriff customer back-office, a dashboard where you can see your end-users' verification data. Depending on your setup, you may be required to access the environment via station.veriff.com or hub.veriff.com. Always **check your sign-up email** and make sure that you **log in via correct address**. A UUID-format unique identifier ([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}) created by you for your end-user to link an end-user to their session(s). Cannot be resolved outside your environment. Veriff stores it only for identity verification and returns it unchanged in webhooks/API responses or as `null` if not provided. Strongly recommended if you already use UUID identifiers. Works as an alternative to `vendorData` in Biometric Authentication solution. A custom unique identifier (max 1,000 characters) created by you, containing only non-semantic data that can't be resolved outside your systems. Veriff returns it unchanged in webhooks/API responses or as `null` if not provided. It's referred to as "unique identifier" in Customer Portal and cannot be changed once set. Required for Fraud solutions (Cross Links check and Velocity Abuse check) and serves as an alternative to `endUserId` in Biometric Authentication when using non-UUID identifiers. 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 where the end-user is directed to go through the verification flow, and it is **unique for each verification session**. It is a combination of the `base URL` and the `sessionToken`, created as soon as a verification session is created. You can find its value in the response payload of your POST /sessions call, as `verification.url`. The data that you send when you make an API request, or that you receive when you get a response.