Payload Structure
When a Face Match or ID Check session completes, Verisoul sends aPOST request to your configured webhook endpoint. A webhook fires for every session outcome: pass, fail, or abandonment.
verification.face-match.completed
Fires when a Face Match session completes
verification.id-check.completed
Fires when an ID Check session completes
If your flow has a client-side dependency (the user is waiting in your UI for a pass/fail result), await the redirect. It fires the moment the session completes.Otherwise, use the webhook. It typically arrives within a few seconds of session completion, though delivery can slow during high-traffic bursts. It is the better fit for backend record-keeping and async processing.You can also use both: await the redirect for the immediate result and treat the webhook as the durable record.
Every webhook Verisoul sends uses the same signing scheme, including these. See Webhook Signature Verification to validate the
x-signature header before processing a payload.Example Success Payload: Face Match
On success,data is exactly what POST /liveness/verify-face would return for the session.
{
"request_id": "fd4c7dc1-32f7-4dfb-99c2-a6daafeaad94",
"session_id": "000575be-fa64-4274-b810-89def4fce2f7",
"project_id": "ed8fe5d7-ead9-4b81-b1b0-74190582341c",
"event_type": "verification.face-match.completed",
"created_at": "2026-08-24T20:43:20.921Z",
"completed_at": "2026-08-24T20:44:04.246Z",
"status": "success",
"data": {
"metadata": {
"project_id": "ed8fe5d7-ead9-4b81-b1b0-74190582341c",
"session_id": "000575be-fa64-4274-b810-89def4fce2f7",
"account_id": null,
"referring_session_id": null,
"request_id": "fd4c7dc1-32f7-4dfb-99c2-a6daafeaad94",
"timestamp": "2026-08-24T20:43:30.655Z"
},
"decision": "Fake",
"risk_score": 1,
"risk_flags": ["repeat_face", "repeat_device"],
"lists": [],
"rules": [],
"device_network_signals": {
"device_risk": 0.4584,
"proxy": 0.4033,
"vpn": 0,
"datacenter": 0,
"tor": 0,
"spoofed_ip": 0,
"recent_fraud_ip": 0,
"device_network_mismatch": 0.0174,
"location_spoofing": 0
},
"referring_session_signals": {
"impossible_travel": 0,
"ip_mismatch": 0,
"user_agent_mismatch": 0,
"device_timezone_mismatch": 0,
"ip_timezone_mismatch": 0
},
"photo_urls": {
"face": "https://storage.googleapis.com/facematch-prod/000575be.../face.jpg?X-Goog-Signature=..."
},
"session_data": {
"true_country_code": "US",
"network": {
"ip_address": "203.0.113.42",
"service_provider": "Google Fiber Inc.",
"connection_type": "isp"
},
"location": {
"continent": "NA",
"country_code": "US",
"state": "Texas",
"city": "Austin",
"zip_code": "78701",
"timezone": "America/Chicago",
"latitude": 30.2672,
"longitude": -97.7431
},
"browser": {
"type": "Chrome",
"version": "150.0.7871.124",
"language": "en-US",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"timezone": "America/Chicago"
},
"device": {
"category": "desktop",
"type": "Mac",
"os": "macOS 26.4.1",
"cpu_cores": 18,
"memory": 32,
"gpu": "ANGLE (Apple, ANGLE Metal Renderer: Apple M5 Pro, Unspecified Version)"
}
},
"matches": {
"num_accounts_linked": 3,
"accounts_linked": [
{ "account_id": "acct_sandbox_test", "match_types": ["face", "browser"] },
{ "account_id": "sandbox_test_2", "match_types": ["face", "browser"] },
{ "account_id": "ben-test-1", "match_types": ["face", "browser"] }
]
},
"video_urls": [
"https://storage.googleapis.com/facematch-prod/000575be.../session_video_1787604230036.webm?X-Goog-Signature=..."
]
},
"error": null
}
Example Success Payload: ID Check
On success,data is exactly what POST /liveness/verify-id would return for the session. It uses the same shape as Face Match plus document_signals and document_data; photo_urls nests inside document_data alongside the ID scan images.
{
"request_id": "dab2f1f9-4b49-4595-9635-64c02228306f",
"session_id": "00035b3e-5b99-4c40-ad07-178c154018ca",
"project_id": "ed8fe5d7-ead9-4b81-b1b0-74190582341c",
"event_type": "verification.id-check.completed",
"created_at": "2026-08-24T20:45:17.691Z",
"completed_at": "2026-08-24T20:48:50.489Z",
"status": "success",
"data": {
"metadata": {
"project_id": "ed8fe5d7-ead9-4b81-b1b0-74190582341c",
"session_id": "00035b3e-5b99-4c40-ad07-178c154018ca",
"account_id": null,
"referring_session_id": null,
"request_id": "dab2f1f9-4b49-4595-9635-64c02228306f",
"timestamp": "2026-08-24T20:45:29.923Z"
},
"decision": "Fake",
"risk_score": 1,
"risk_flags": ["moderate_id_face_match_score", "repeat_face", "repeat_id", "repeat_device"],
"document_signals": {
"id_age": 29,
"face_age_estimate": "over25",
"id_face_match_score": 0.45,
"id_barcode_status": "success",
"id_face_status": "likely_original_face",
"id_text_status": "likely_original_text",
"is_id_digital_spoof": "likely_physical_id",
"is_full_id_captured": "full_id_detected",
"id_validity": "likely_authentic_id"
},
"device_network_signals": {
"ip_document_country_mismatch": false,
"device_risk": false,
"proxy": false,
"vpn": false,
"datacenter": false,
"tor": false,
"spoofed_ip": false,
"recent_fraud_ip": false,
"device_network_mismatch": false
},
"referring_session_signals": {
"impossible_travel": false,
"ip_mismatch": false,
"user_agent_mismatch": false
},
"document_data": {
"template_info": {
"document_country_code": "US",
"document_country": "United States",
"document_state": "Massachusetts",
"template_type": "driver_license"
},
"user_data": {
"first_name": "Jane",
"last_name": "Doe",
"date_of_birth": "01/15/1995",
"date_of_expiration": "01/15/2029",
"date_of_issue": "01/10/2024",
"id_number": "X12345678",
"id_number2": null,
"address": {
"city": "Boston",
"country": "US",
"postal_code": "02108",
"state": "MA",
"street": "1 Main St"
}
},
"photo_urls": {
"face": "https://storage.googleapis.com/facematch-prod/00035b3e.../face.jpg?X-Goog-Signature=...",
"id_scan_back": "https://storage.googleapis.com/facematch-prod/00035b3e.../id_scan_back.jpg?X-Goog-Signature=...",
"id_scan_front": "https://storage.googleapis.com/facematch-prod/00035b3e.../id_scan_front.jpg?X-Goog-Signature=..."
}
},
"session_data": {
"network": {
"ip_address": "203.0.113.42",
"service_provider": "Google Fiber Inc.",
"connection_type": "isp"
},
"location": {
"continent": "NA",
"country_code": "US",
"state": "Texas",
"city": "Austin",
"zip_code": "78701",
"timezone": "America/Chicago",
"latitude": 30.2672,
"longitude": -97.7431
},
"browser": {
"type": "Chrome",
"version": "150.0.7871.124",
"language": "en-US",
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36",
"timezone": "America/Chicago"
},
"device": {
"category": "desktop",
"type": "Mac",
"os": "macOS 26.4.1",
"cpu_cores": 18,
"memory": 32,
"gpu": "ANGLE (Apple, ANGLE Metal Renderer: Apple M5 Pro, Unspecified Version)"
}
},
"matches": {
"num_accounts_linked": 3,
"accounts_linked": [
{ "account_id": "acct_sandbox_test", "match_types": ["face", "browser"] },
{ "account_id": "sandbox_test_2", "match_types": ["face", "browser", "document_number", "document_name"] },
{ "account_id": "ben-test-1", "match_types": ["face", "browser", "document_number"] }
]
},
"video_urls": [
"https://storage.googleapis.com/facematch-prod/00035b3e.../session_video_1787604461595.webm?X-Goog-Signature=...",
"https://storage.googleapis.com/facematch-prod/00035b3e.../session_video_1787604521797.webm?X-Goog-Signature=..."
]
},
"error": null
}
Success payloads contain PII (name, date of birth, ID number, address for ID Check) and signed, time-limited URLs to photo/video evidence. URLs are signed at the moment the webhook is sent, so their expiration window starts when you receive them and lasts for 60 minutes. Treat the payload itself as sensitive data.
Example Error Payload
{
"request_id": "67c334e0-b01c-427d-8425-d32c144a2e52",
"session_id": "00058a40-0b02-431f-9115-ee9983c10e13",
"project_id": "ed8fe5d7-ead9-4b81-b1b0-74190582341c",
"event_type": "verification.face-match.completed",
"created_at": "2026-08-18T20:13:26.762Z",
"completed_at": "2026-08-18T20:15:44.799Z",
"status": "error",
"data": null,
"error": {
"code": "face_match_failed",
"message": "The user failed the face match check after the maximum number of attempts"
}
}
Field Reference
Top-Level Fields
| Field | Type | Description |
|---|---|---|
request_id | string | Unique identifier for this webhook. On success, matches data.metadata.request_id. |
session_id | string | The verification session ID. Present on both success and error, so use it to correlate the webhook with your session. |
project_id | string | Your Verisoul project ID |
event_type | string | verification.face-match.completed or verification.id-check.completed |
created_at | string | When the verification session was created (ISO 8601) |
completed_at | string | When the session completed (ISO 8601) |
status | string | success or error |
data | object | null | The full verification result (present on success) |
error | object | null | Error details (present on failure) |
data
The full verification result, identical to the verify-face or verify-id API response. For field-by-field definitions, see:
error
| Field | Type | Description |
|---|---|---|
code | string | Error code (see Error Codes below) |
message | string | Human-readable description of the failure |
Error Codes
| Code | Meaning |
|---|---|
liveness_check_failed | The session ended in a non-success state, for example the user cancelled a step. |
face_match_failed | The face match/liveness step reached the maximum number of attempts without succeeding. |
failed_to_process_id_scan | The identity document scan could not be processed (ID Check only). |
failed_to_collect_device_data | Required device or network data could not be collected from the user’s browser. |
max_duration_exceeded | The session was never completed and can no longer be completed. Sessions stay completable for 30 days after creation, so this can arrive well after the user last interacted with the flow. |
The redirect’s
error_message vocabulary is broader than this list. invalid_session_id and session_id_not_found appear only in a redirect; a webhook fires only for sessions that were found and valid.Delivery Guarantees
- Exactly once per session. Each session fires exactly one webhook, for whichever terminal state it reaches first. This holds even if the user abandons the session or
verify-face/verify-idis never called. - Signed. Every payload includes an
x-signatureheader. See Webhook Signature Verification for how to verify it. - Retried with backoff if your endpoint returns a non-2xx response.
