Identity Verification
Perform comprehensive identity verification with document checks and liveness detection. The consumer completes verification tasks via the Thirdfort mobile app.
Overview
Use Case: Full identity verification when the consumer is in the flow and can use the mobile app to capture documents and complete liveness checks.
Key Features:
- Document capture (passport, driving license, ID card)
- Liveness detection (selfie video)
- AML screening (sanctions/PEP checks)
- Optional address verification
- Optional CCJ/Insolvency check (UK only)
- Optional ongoing monitoring
- Consumer completes tasks via mobile app
Subject Type: Individual
Template ID: checkTemplates/identity-verification-check-v1-0-0
When to Use This Check
✅ Good for:
- Full identity verification with document checks
- Onboarding new clients who can use mobile app
- Regulatory compliance requiring document verification
- High-assurance identity verification
❌ Not suitable for:
- Quick screening without consumer interaction (use Client-Only Verification instead)
- Source of funds verification (use Source of Funds instead)
- Business verification (use KYB Verification instead)
Consumer Journey
- Client creates check via API
- Consumer receives notification (email/SMS with magic link)
- Consumer opens Thirdfort app via magic link
- Consumer captures documents (passport, driving license, or ID card)
- Consumer completes liveness check (selfie video)
- Consumer provides additional data (address, date of birth if not on document)
- Check processes (document verification, liveness, AML screening)
- Results available via API
Typical completion time: 5-15 minutes (depends on consumer)
Prerequisites
- Thirdfort account with API access
- Client credentials (Client ID and Secret)
- Consumer contact details: Email or phone number for notification
- Package support: Ongoing monitoring requires package support (if enabled)
Parameters Reference
Required Parameters
| Parameter | Type | Description |
|---|---|---|
displayName | string | Human-readable name for the check |
clientReference | string | Your own reference ID for tracking |
template | string | Must be checkTemplates/identity-verification-check-v1-0-0 |
params.@type | string | Must be type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckParams |
params.subject.givenName | string | First name of the individual |
params.subject.familyName | string | Last name of the individual |
params.subject.email OR params.subject.phoneNumber | string | Contact method for consumer notification |
Optional Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
params.subject.otherNames | string | - | Middle names |
params.subject.dateOfBirth | Date | - | Date of birth (structured object: {year, month, day}) |
params.subject.yearOfBirth | uint32 | - | Year of birth (alternative to full date) |
params.address | Address | - | Residential address (if known) |
params.enableOngoingMonitoring | bool | false | Continuous AML screening monitoring |
params.requireAddressVerification | bool | false | Electronic address matching & verification |
params.requireCcjInsolvency | bool | false | Surface CCJs or insolvency indicators on an individual (UK addresses only) |
params.internationalAddressVerificationConsent | bool | false | Required for non-UK addresses if address verification is enabled |
Complete Example
Create Check Request
curl -X POST "https://api.thirdfort.dev/client/api/v1/organizations/{org_id}/teams/{team_id}/checks" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"displayName": "Identity verification for Jane Smith",
"clientReference": "client-12345",
"template": "checkTemplates/identity-verification-check-v1-0-0",
"params": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckParams",
"subject": {
"givenName": "Jane",
"familyName": "Smith",
"email": "jane.smith@example.com",
"dateOfBirth": {
"year": 1990,
"month": 6,
"day": 15
}
},
"address": {
"buildingNumber": "123",
"street": "High Street",
"locality": "London",
"postalCode": "SW1A 1AA",
"countryCode": "GBR"
},
"enableOngoingMonitoring": true,
"requireAddressVerification": true
}
}'
Note: The endpoint includes the parent (team) in the URL path. Replace {org_id} and {team_id} with your actual organization and team IDs.
Response
{
"name": "organizations/NT6bqXp6k47SbagGAUHHG7/teams/gZzg3caveKLhe3VXjRiyXL/checks/eaa99a49-7c7c-43e0-a929-ec2dddec8a85",
"displayName": "Identity verification for Jane Smith",
"clientReference": "client-12345",
"state": "ACTIVE",
"createTime": "2026-03-06T14:06:59.758655Z",
"updateTime": null,
"template": "checkTemplates/identity-verification-check-v1-0-0",
"params": { ... },
"relatedSubjects": [ ... ],
"creator": "partners/thirdfort/integrations/4",
"ongoingMonitoring": {
"enabled": true,
"activeUntil": null
}
}
Summary Response
{
"name": "organizations/.../teams/.../checks/.../checkSummary",
"createTime": "2026-03-06T14:07:00.537001Z",
"payload": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckSummary",
"overallRecommendation": {
"recommendation": "CLEAR",
"description": "No concerning issues found"
},
"identityDocumentCheckResult": { ... },
"livenessCheckResult": { ... },
"screeningCheckResult": { ... },
"addressVerificationCheckResult": { ... },
"ccjInsolvencyCheckResult": null,
"providedSubjectData": { ... }
},
"sourceFindings": [ ... ],
"reportUrl": "https://files.thirdfort.dev/client/downloads/objects/6ff46f10-ae87-42e6-8601-1f0c32ed5ba6",
"summaryReportUrl": "https://files.thirdfort.dev/client/downloads/objects/8df632f9-e3f9-4e9e-88aa-ca449debf3b8"
}
Result Fields
| Field | Description |
|---|---|
payload.overallRecommendation | Overall check recommendation object with recommendation and description |
payload.identityDocumentCheckResult | Document verification results - always included |
payload.livenessCheckResult | Liveness detection results - always included |
payload.screeningCheckResult | AML screening results (sanctions/PEP) - always included |
payload.addressVerificationCheckResult | Address verification results - only if requireAddressVerification: true |
payload.ccjInsolvencyCheckResult | CCJ/Insolvency results - only if requireCcjInsolvency: true and UK address |
payload.providedSubjectData | Echo of the subject data you provided |
reportUrl | Download link for full PDF report (top-level field) |
summaryReportUrl | Download link for summary PDF report (top-level field) |
sourceFindings | Array of finding resource names that contributed to this summary |
Recommendation Values
CLEAR: No concerning issues found - proceed with confidenceCONSIDER: Anomalies detected that may be explainable - review findingsFAIL: Serious anomalies detected, unlikely explainable - high risk
Monitoring Check Progress
Identity verification checks require consumer interaction and may take several minutes to complete. You can monitor progress using either notifications (recommended) or check status polling.
Option 1: Notifications (Recommended)
Receive real-time updates when the check completes or status changes.
Polling for Notifications
Poll the notifications endpoint to retrieve updates:
GET /v1/organizations/{organization}/notifications?page_size=25
Example: Poll for check completion
import requests
import time
def poll_for_check_completion(organization, check_name, access_token, timeout_seconds=600):
"""
Poll for check completion notification.
Args:
organization: Organization ID (e.g., 'acme-corp')
check_name: Full check resource name
access_token: OAuth access token
timeout_seconds: Maximum time to wait (default: 10 minutes)
Returns:
Notification dict when check completes, or None if timeout
"""
base_url = "https://api.thirdfort.dev/client/api"
headers = {"Authorization": f"Bearer {access_token}"}
start_time = time.time()
cursor = None
while time.time() - start_time < timeout_seconds:
# Build request URL
url = f"{base_url}/v1/organizations/{organization}/notifications"
params = {"page_size": 25}
if cursor:
params["page_token"] = cursor
# Poll for notifications
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
data = response.json()
notifications = data.get("notifications", [])
# Check for check completion notification
for notification in notifications:
if notification["type"] == "notification.client.check_complete.v1":
payload = notification["payload"]
if payload.get("check") == check_name:
print(f"Check completed with recommendation: {payload['recommendation']}")
return notification
# Update cursor for next poll
if "nextPageToken" in data:
cursor = data["nextPageToken"]
# Wait before next poll
time.sleep(30)
print("Timeout waiting for check completion")
return None
# Usage
notification = poll_for_check_completion(
organization="acme-corp",
check_name="organizations/acme-corp/teams/default/checks/01JRA3XYZ789",
access_token="your_access_token"
)
if notification:
# Check completed - retrieve results
check_name = notification["payload"]["check"]
# ... fetch check summary and findings
Notification Types:
notification.client.check_complete.v1- Check has completed processingnotification.client.report_generated.v1- Report has been generated (e.g., after finding review)
Best Practices:
- Store the
nextPageTokenbetween polls to avoid missing notifications - Poll every 30-60 seconds (avoid more frequent polling)
- Use notification ID for deduplication
- Filter by notification type to reduce processing
For comprehensive polling implementation details, see the Polling for Notifications guide.
Webhooks
For real-time push delivery, Thirdfort can configure webhook endpoints to receive notifications as they occur. Contact your Thirdfort account manager or email api-support@thirdfort.com to set up webhook delivery.
Option 2: Check Status Polling
Alternatively, poll the check resource directly to monitor state changes:
# Poll check status every 30 seconds
curl -X GET "https://api.thirdfort.dev/client/api/v1/organizations/{org_id}/teams/{team_id}/checks/{check_id}" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Check States:
ACTIVE- Check is processing or waiting for consumerINACTIVE- Check has completed, results availableCANCELLED- Check was cancelledDELETED- Check was soft-deleted
When to use check status polling:
- You only need to monitor a single check
- You don't need to track other events (report generation, monitoring hits)
- You prefer simpler implementation
When to use notification polling:
- You need to monitor multiple checks
- You want to track all events (completion, reports, monitoring)
- You want more efficient API usage
Common Configurations
Basic Identity Verification
Minimal configuration for identity verification:
{
"displayName": "Identity verification for Jane Smith",
"clientReference": "client-12345",
"template": "checkTemplates/identity-verification-check-v1-0-0",
"params": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckParams",
"subject": {
"givenName": "Jane",
"familyName": "Smith",
"email": "jane.smith@example.com"
}
}
}
With Ongoing Monitoring
Enable continuous sanctions monitoring:
{
"params": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckParams",
"subject": { ... },
"enableOngoingMonitoring": true
}
}
With Address Verification
Verify the provided or consumer-entered address:
{
"params": {
"@type": "type.googleapis.com/thirdfort.client.checks.type.v1.IdentityVerificationCheckParams",
"subject": { ... },
"address": {
"buildingNumber": "123",
"street": "High Street",
"locality": "London",
"postalCode": "SW1A 1AA",
"countryCode": "GBR"
},
"requireAddressVerification": true
}
}
Best Practices
Provide Known Data
If you already have the consumer's information, provide it in the check parameters:
{
"subject": {
"givenName": "Jane",
"familyName": "Smith",
"email": "jane.smith@example.com",
"dateOfBirth": {
"year": 1990,
"month": 6,
"day": 15
}
},
"address": { ... }
}
This pre-fills the mobile app and improves the consumer experience.
Consumer Notifications
- Provide either
emailorphoneNumber(or both) - Email notifications include a magic link to open the app
- SMS notifications include a link to download the app
- Consumers can complete verification on any device
Handling Incomplete Checks
If a consumer doesn't complete verification:
- Check remains in
ACTIVEstate - You can cancel the check via API
- You can create a new check for the same consumer
Troubleshooting
Common Issues
Consumer didn't receive notification
- Verify email/phone number is correct
- Check spam folder (for email)
- Resend notification via API (if supported)
Check stuck in ACTIVE state
- Consumer may not have completed all tasks
- Check consumer's progress via mobile app
- Consider cancelling and creating new check
400 Bad Request - "field required"
- Ensure
displayNameandclientReferenceare included - Verify
@typefield is present inparams - Check that
dateOfBirthuses structured object format (not string) - Ensure either
emailorphoneNumberis provided
404 Not Found
- Verify the endpoint includes parent in URL:
/v1/{parent}/checks - Check that organization and team IDs are correct
- Ensure endpoint is
/checkSummarynot/summary