Identity Verification API
Programmatically create and manage identity verification sessions for individual entities. Send secure verification links via email, monitor progress in real-time, and retrieve validated identity data.
Create verification sessions, send secure links via email, and receive webhook notifications when verification completes. Extract verified identity data including name, date of birth, document details, and more.
Key Features
- Automated email delivery - Secure verification links sent directly to individuals
- Flexible profiles - Choose from basic, standard, or comprehensive checks
- Custom configurations - Define exact verification checks programmatically
- Real-time webhooks - Instant notifications for all verification events
Credits are charged per check when verification completes successfully. Session creation itself is free. Incomplete or failed verifications are not charged. Test mode sessions never consume live credits.
Verification Session Object
A verification session represents a complete identity verification workflow for an individual entity.
Core Attributes
| Field | Type | Description |
|---|---|---|
session_id | uuid | Unique identifier for the verification session |
entity_id | uuid | ID of the individual entity being verified |
entity_name | string | Name of the individual being verified |
status | string | Workflow state: pending, accessed, completed, expired, revoked, failed |
outcome | string | Verification result: pending, clear, consider, attention, issue, error |
failure_reason | string | Reason for non-clear outcome (e.g. document_fake, face_mismatch) |
failure_details | string | Extended description of the failure |
verification_url | string | Base verification URL (token is in the email only, not returned by the API) |
email_sent | boolean | Whether verification email was sent |
delivery_method | string | Delivery method used (e.g. email) |
accessed_at | datetime | When user first opened verification link |
completed_at | datetime | When verification completed |
expires_at | datetime | Link expiration timestamp (default 48 hours) |
created_at | datetime | Session creation timestamp (ISO 8601) |
checks | array | Array of individual check results (returned by status and results endpoints) |
Status Values
| Status | Description |
|---|---|
pending | Session created, link not yet accessed |
accessed | User opened verification link |
completed | All checks completed |
expired | Verification link expired (default 48 hours) |
revoked | Session canceled via API |
failed | Verification failed (see failure_reason) |
Outcome Values
| Outcome | Description |
|---|---|
pending | Verification not yet completed |
clear | All checks passed successfully |
consider | Manual review recommended |
attention | Issues detected, review required |
issue | Verification failed |
error | Technical error during verification |
Create Verification Session
Create a new identity verification session for an individual entity and optionally send a secure verification link via email.
/api/v1/verification/sessions/
/api/v2/verification/sessions/
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
entity_id | uuid | Yes | ID of entity to verify (must be entity_type: individual) |
email | string | Yes | Email address to send verification link to |
verification_profile | string | No | Preset profile: basic, standard (default), comprehensive |
verification_checks | object | No | Custom check configuration - overrides profile if provided |
expiry_hours | integer | No | Hours until link expires (default: 48, max: 168) |
send_email | boolean | No | Automatically send email (default: true) |
webhook_url | string | No | Session-specific webhook URL for verification events |
Verification Profiles
| Profile | Checks Included | Use Case |
|---|---|---|
basic | Document check only | Basic ID verification |
standard | Document + Liveness | Standard KYC |
comprehensive | Document + Liveness + AML + PEP | High-risk onboarding |
Custom Verification Checks
Override a profile by passing verification_checks. Accepts simplified boolean or full format with options.
| Check Type | Shorthand | Description |
|---|---|---|
document_check | - | Validates document authenticity, detects forgery |
identity_check | photo_check | Face match between document photo and selfie |
enhanced_identity_check | video_check / liveness_check | Liveness detection via video (prevents spoofing) |
proof_of_address_check | poa_check | Validates utility bills, bank statements |
Create Session (Standard Profile)
curl -X POST https://api.kycgenie.com/api/v1/verification/sessions/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"verification_profile": "standard",
"expiry_hours": 48,
"send_email": true
}'
curl -X POST https://api.kycgenie.com/api/v2/verification/sessions/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"verification_profile": "standard",
"expiry_hours": 48,
"send_email": true
}'
import requests
import uuid
response = requests.post(
"https://api.kycgenie.com/api/v1/verification/sessions/",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"verification_profile": "standard",
"expiry_hours": 48,
"send_email": True,
}
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
session = client.identity_verification.create(
entity_id="550e8400-e29b-41d4-a716-446655440000",
email="john.doe@example.com",
verification_profile="standard",
expiry_hours=48,
send_email=True,
)
print(session.session_id)
print(session.status) # "pending"
print(session.email_sent) # True
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
entity_id: "550e8400-e29b-41d4-a716-446655440000",
email: "john.doe@example.com",
verification_profile: "standard",
expiry_hours: 48,
send_email: true,
}),
}
);
const data = await response.json();
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
entity_id: "550e8400-e29b-41d4-a716-446655440000",
email: "john.doe@example.com",
verification_profile: "standard",
expiry_hours: 48,
send_email: true,
}),
}
);
const data = await response.json();
Custom Checks Example
curl -X POST https://api.kycgenie.com/api/v1/verification/sessions/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"verification_checks": {
"document_check": true,
"photo_check": true,
"video_check": false,
"poa_check": true
},
"webhook_url": "https://your-domain.com/webhooks/verification"
}'
curl -X POST https://api.kycgenie.com/api/v2/verification/sessions/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"verification_checks": {
"document_check": true,
"photo_check": true,
"video_check": false,
"poa_check": true
},
"webhook_url": "https://your-domain.com/webhooks/verification"
}'
import requests, uuid
response = requests.post(
"https://api.kycgenie.com/api/v1/verification/sessions/",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"verification_checks": {
"document_check": True,
"photo_check": True,
"video_check": False,
"poa_check": True,
},
"webhook_url": "https://your-domain.com/webhooks/verification",
}
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
session = client.identity_verification.create(
entity_id="550e8400-e29b-41d4-a716-446655440000",
email="john.doe@example.com",
verification_checks={
"document_check": True,
"photo_check": True,
"video_check": False,
"poa_check": True,
},
webhook_url="https://your-domain.com/webhooks/verification",
)
print(session.session_id)
const baseUrl = $store.docs.version === "v2"
? "https://api.kycgenie.com/api/v2/"
: "https://api.kycgenie.com/api/v1/";
const response = await fetch(`${baseUrl}verification/sessions/`, {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
entity_id: "550e8400-e29b-41d4-a716-446655440000",
email: "john.doe@example.com",
verification_checks: {
document_check: true,
photo_check: true,
video_check: false,
poa_check: true,
},
webhook_url: "https://your-domain.com/webhooks/verification",
}),
});
const data = await response.json();
Success Response (202 Accepted)
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_name": "John Doe",
"status": "pending",
"verification_url": "https://kycgenie.com/verify/770e8400-e29b-41d4-a716-446655440002",
"email_sent": true,
"expires_at": "2026-06-14T12:00:00Z",
"created_at": "2026-06-12T12:00:00Z"
}
Error - 400 Invalid Entity Type
{
"error": "Identity verification is only available for individuals.",
"code": "INVALID_REQUEST",
"details": {
"entity_type": "company",
"entity_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
Error - 409 Active Session Exists
{
"error": "Active verification session already exists.",
"code": "CONFLICT",
"details": {
"existing_session_id": "880e8400-e29b-41d4-a716-446655440003",
"status": "pending",
"expires_at": "2026-06-14T10:00:00Z",
"created_at": "2026-06-12T10:00:00Z"
}
}
Get Verification Session Status
Retrieve current status, outcome, and individual check details for a verification session.
/api/v1/verification/sessions/{session_id}/
/api/v2/verification/sessions/{session_id}/
Returns session status with 200 OK.
Get Session Status
curl https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/ \
-H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/ \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
response = requests.get(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
session = client.identity_verification.get_session(
session_id="770e8400-e29b-41d4-a716-446655440002",
)
print(session.status) # "completed"
print(session.outcome) # "clear"
print(len(session.checks)) # 2
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/",
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
console.log(data.status, data.outcome);
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/",
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
console.log(data.status, data.outcome);
Success Response (200 OK)
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_name": "John Doe",
"status": "completed",
"outcome": "clear",
"failure_reason": null,
"failure_details": "",
"delivery_method": "email",
"accessed_at": "2026-06-12T12:05:00Z",
"completed_at": "2026-06-12T12:15:00Z",
"expires_at": "2026-06-14T12:00:00Z",
"created_at": "2026-06-12T12:00:00Z",
"checks": [
{
"check_id": "990e8400-e29b-41d4-a716-446655440004",
"check_type": "document_check",
"status": "completed",
"outcome": "clear",
"created_at": "2026-06-12T12:05:00Z",
"completed_at": "2026-06-12T12:10:00Z"
},
{
"check_id": "aa0e8400-e29b-41d4-a716-446655440005",
"check_type": "enhanced_identity_check",
"status": "completed",
"outcome": "clear",
"created_at": "2026-06-12T12:10:00Z",
"completed_at": "2026-06-12T12:15:00Z"
}
]
}
Get Detailed Verification Results
Retrieve complete verification results including extracted identity data and raw check data.
Only available when session status is completed.
/api/v1/verification/sessions/{session_id}/results/
/api/v2/verification/sessions/{session_id}/results/
Detailed results are only available when status: completed. Requesting before completion returns 400. Test mode sessions return limited extracted data.
Get Detailed Results
curl https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/results/ \
-H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/results/ \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
response = requests.get(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/results/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
results = client.identity_verification.get_results(
session_id="770e8400-e29b-41d4-a716-446655440002",
)
data = results.extracted_data
print(data.first_name, data.last_name)
print(data.document_type, data.document_number)
for check in results.checks:
print(check.check_type, check.outcome)
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/results/",
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/results/",
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
Success Response (200 OK)
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"outcome": "clear",
"extracted_data": {
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1985-05-15",
"document_type": "passport",
"document_number": "P12345678",
"document_country": "GB",
"nationality": "GB",
"expiry_date": "2030-05-15",
"gender": "male",
"address": {
"line1": "123 Main Street",
"city": "London",
"postcode": "SW1A 1AA",
"country": "GB"
}
},
"checks": [
{
"check_id": "990e8400-e29b-41d4-a716-446655440004",
"check_type": "document_check",
"status": "completed",
"outcome": "clear",
"created_at": "2026-06-12T12:05:00Z",
"completed_at": "2026-06-12T12:10:00Z",
"result_data": {
"id": "5e8a2b1f-5f3d-4c8a-9b2d-8e7f6a5b4c3d",
"type": "document_check",
"result": "clear",
"breakdown": {
"documentValidation": "clear",
"imageQuality": "clear",
"visualAuthenticity": "clear"
}
}
}
]
}
Error - 400 Session Not Completed
{
"error": "Verification session not completed.",
"code": "INVALID_REQUEST",
"details": {
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"current_status": "pending"
}
}
Resend Verification Link
Resend a verification link via email to the same or a different address. Maximum 3 resends per session.
/api/v1/verification/sessions/{session_id}/resend/
/api/v2/verification/sessions/{session_id}/resend/
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | No | New email address; omit to resend to the original address |
Resend Verification Link
curl -X POST https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/resend/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"email": "john.doe.work@example.com"}'
curl -X POST https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/resend/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"email": "john.doe.work@example.com"}'
import requests, uuid
response = requests.post(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/resend/",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"email": "john.doe.work@example.com"},
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
client.identity_verification.resend(
session_id="770e8400-e29b-41d4-a716-446655440002",
email="john.doe.work@example.com", # omit to resend to original address
)
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/resend/",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({ email: "john.doe.work@example.com" }),
}
);
const data = await response.json();
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/resend/",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({ email: "john.doe.work@example.com" }),
}
);
const data = await response.json();
Success Response (200 OK)
{
"success": true,
"message": "Verification link resent successfully",
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"email_sent_to": "john.doe.work@example.com",
"resend_count": 1
}
Error - 429 Max Resends Reached
{
"error": "Too many resend attempts. Please create a new verification session.",
"code": "RATE_LIMITED",
"details": {
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"resend_count": 3
}
}
Revoke Verification Session
Cancel and revoke a verification session. The verification link will no longer work.
Cannot revoke a session that is already completed, expired, or revoked.
/api/v1/verification/sessions/{session_id}/revoke/
/api/v2/verification/sessions/{session_id}/revoke/
Revoke Session
curl -X DELETE https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/revoke/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"
curl -X DELETE https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/revoke/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)"
import requests, uuid
response = requests.delete(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/revoke/",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": str(uuid.uuid4()),
},
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
client.identity_verification.revoke_session(
session_id="770e8400-e29b-41d4-a716-446655440002",
)
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/revoke/",
{
method: "DELETE",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": crypto.randomUUID(),
},
}
);
const data = await response.json();
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/revoke/",
{
method: "DELETE",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": crypto.randomUUID(),
},
}
);
const data = await response.json();
Success Response (200 OK)
{
"success": true,
"message": "Verification session revoked",
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "revoked"
}
Error - 400 Already Completed
{
"error": "Cannot revoke completed session",
"code": "INVALID_REQUEST",
"details": {
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "completed",
"completed_at": "2026-06-12T12:15:00Z"
}
}
List Entity Verification Sessions
Retrieve all verification sessions for a specific entity with optional filtering.
/api/v1/entities/{entity_id}/verification-sessions/
/api/v2/entities/{entity_id}/verification-sessions/
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: pending, accessed, completed, expired, revoked, failed |
outcome | string | Filter: pending, clear, consider, attention, issue, error |
limit | integer | Results per page (default: 10) |
offset | integer | Pagination offset (default: 0) |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter: pending, accessed, completed, expired, revoked, failed |
outcome | string | Filter: pending, clear, consider, attention, issue, error |
after | string | Cursor for next page (from next_cursor) |
before | string | Cursor for previous page (from prev_cursor) |
page_size | integer | Results per page (default: 50, max: 100) |
List Sessions for Entity
curl "https://api.kycgenie.com/api/v1/entities/550e8400-e29b-41d4-a716-446655440000/verification-sessions/?status=completed&limit=20" \
-H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.kycgenie.com/api/v2/entities/550e8400-e29b-41d4-a716-446655440000/verification-sessions/?status=completed&page_size=20" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
response = requests.get(
"https://api.kycgenie.com/api/v1/entities/550e8400-e29b-41d4-a716-446655440000/verification-sessions/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"status": "completed", "limit": 20},
)
data = response.json()
print(f"Total: {data['count']}")
for session in data['results']:
print(session['session_id'], session['status'], session['outcome'])
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
result = client.identity_verification.list_entity_sessions(
entity_id="550e8400-e29b-41d4-a716-446655440000",
)
for session in result.results:
print(session.session_id, session.status, session.outcome)
const params = new URLSearchParams({ status: "completed", limit: 20 });
const response = await fetch(
`https://api.kycgenie.com/api/v1/entities/550e8400-e29b-41d4-a716-446655440000/verification-sessions/?${params}`,
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
console.log(`Total: ${data.count}`);
data.results.forEach(s => console.log(s.session_id, s.status));
const params = new URLSearchParams({ status: "completed", page_size: 20 });
const response = await fetch(
`https://api.kycgenie.com/api/v2/entities/550e8400-e29b-41d4-a716-446655440000/verification-sessions/?${params}`,
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
data.results.forEach(s => console.log(s.session_id, s.status));
if (data.has_more) console.log("Next cursor:", data.next_cursor);
Response Example
{
"count": 5,
"limit": 20,
"offset": 0,
"results": [
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "completed",
"outcome": "clear",
"failure_reason": null,
"created_at": "2026-06-12T12:00:00Z",
"completed_at": "2026-06-12T12:15:00Z"
}
]
}
{
"has_more": false,
"next_cursor": null,
"prev_cursor": null,
"results": [
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "completed",
"outcome": "clear",
"failure_reason": null,
"created_at": "2026-06-12T12:00:00Z",
"completed_at": "2026-06-12T12:15:00Z"
}
]
}
List All Verification Sessions
Retrieve all verification sessions across all entities in your tenant, with optional filtering by status, outcome, and entity.
/api/v1/verification/sessions/list/
/api/v2/verification/sessions/list/
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by session status |
outcome | string | Filter by outcome |
entity_id | uuid | Filter by entity |
limit | integer | Results per page (default: 50, max: 200) |
offset | integer | Pagination offset (default: 0) |
Query Parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by session status |
outcome | string | Filter by outcome |
entity_id | uuid | Filter by entity |
after | string | Cursor for next page |
page_size | integer | Results per page (default: 50, max: 100) |
List All Sessions
curl "https://api.kycgenie.com/api/v1/verification/sessions/list/?status=pending&limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.kycgenie.com/api/v2/verification/sessions/list/?status=pending&page_size=50" \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
response = requests.get(
"https://api.kycgenie.com/api/v1/verification/sessions/list/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
params={"status": "pending", "limit": 50},
)
data = response.json()
print(f"Total: {data['count']}")
for session in data['results']:
print(session['session_id'], session['status'])
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
result = client.identity_verification.list_sessions(
status="pending",
page_size=50,
)
for session in result.results:
print(session.session_id, session.status)
# Paginate through all results
while result.has_more:
result = client.identity_verification.list_sessions(
status="pending",
after=result.next_cursor,
page_size=50,
)
for session in result.results:
print(session.session_id, session.status)
const params = new URLSearchParams({ status: "pending", limit: 50 });
const response = await fetch(
`https://api.kycgenie.com/api/v1/verification/sessions/list/?${params}`,
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
console.log(`Total: ${data.count}`);
const params = new URLSearchParams({ status: "pending", page_size: 50 });
const response = await fetch(
`https://api.kycgenie.com/api/v2/verification/sessions/list/?${params}`,
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
data.results.forEach(s => console.log(s.session_id, s.status));
if (data.has_more) console.log("Next cursor:", data.next_cursor);
Response Example
{
"count": 42,
"limit": 50,
"offset": 0,
"results": [
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "pending",
"outcome": "pending",
"failure_reason": null,
"created_at": "2026-06-12T12:00:00Z",
"completed_at": null
}
]
}
{
"has_more": true,
"next_cursor": "eyJpZCI6IjdmMjM0NTY3In0",
"prev_cursor": null,
"results": [
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"status": "pending",
"outcome": "pending",
"failure_reason": null,
"created_at": "2026-06-12T12:00:00Z",
"completed_at": null
}
]
}
Create Verification Review
Submit a manual review decision for a completed verification session. Allows compliance officers to approve, reject, or flag verifications with a full audit trail.
/api/v1/verification/sessions/{session_id}/reviews/create/
/api/v2/verification/sessions/{session_id}/reviews/create/
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
decision | string | Yes | approved, rejected, flagged, pending |
notes | string | Yes | Reviewer notes explaining the decision |
check_ids | array[uuid] | No | Specific check IDs if review is check-specific |
Create Review
curl -X POST https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/create/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"decision": "approved",
"notes": "Identity verified successfully. All checks clear."
}'
curl -X POST https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/create/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"decision": "approved",
"notes": "Identity verified successfully. All checks clear."
}'
import requests, uuid
response = requests.post(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/create/",
headers={
"Authorization": "Bearer YOUR_API_KEY",
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"decision": "approved",
"notes": "Identity verified successfully. All checks clear.",
},
)
print(response.json())
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
review = client.identity_verification.create_review(
session_id="770e8400-e29b-41d4-a716-446655440002",
decision="approved",
notes="Identity verified successfully. All checks clear.",
)
print(review.review_id)
print(review.decision) # "approved"
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/create/",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
decision: "approved",
notes: "Identity verified successfully. All checks clear.",
}),
}
);
const review = await response.json();
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/create/",
{
method: "POST",
headers: {
"Authorization": "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
decision: "approved",
notes: "Identity verified successfully. All checks clear.",
}),
}
);
const review = await response.json();
Success Response (201 Created)
{
"review_id": "120e8400-e29b-41d4-a716-446655440012",
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"decision": "approved",
"notes": "Identity verified successfully. All checks clear.",
"reviewed_by": {
"id": "130e8400-e29b-41d4-a716-446655440013",
"name": "Jane Smith",
"email": "jane.smith@company.com"
},
"reviewed_at": "2026-06-12T15:00:00Z",
"check_ids": null
}
Error - 400 Session Not Completed
{
"error": "Cannot review verification session",
"code": "INVALID_REQUEST",
"details": {
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"current_status": "pending"
}
}
List Verification Reviews
Retrieve all review decisions for a verification session, ordered most recent first.
/api/v1/verification/sessions/{session_id}/reviews/
/api/v2/verification/sessions/{session_id}/reviews/
List Reviews
curl https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/ \
-H "Authorization: Bearer YOUR_API_KEY"
curl https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/ \
-H "Authorization: Bearer YOUR_API_KEY"
import requests
response = requests.get(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
)
data = response.json()
for review in data['reviews']:
print(review['decision'], review['reviewed_at'])
from kycgenie import KYCGenie
client = KYCGenie(api_key="YOUR_API_KEY")
reviews = client.identity_verification.list_session_reviews(
session_id="770e8400-e29b-41d4-a716-446655440002",
)
print(f"Latest decision: {reviews.latest_decision}")
for review in reviews.results:
print(review.decision, review.reviewed_at)
const response = await fetch(
"https://api.kycgenie.com/api/v1/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/",
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
data.reviews.forEach(r => console.log(r.decision, r.reviewed_at));
const response = await fetch(
"https://api.kycgenie.com/api/v2/verification/sessions/770e8400-e29b-41d4-a716-446655440002/reviews/",
{ headers: { "Authorization": "Bearer YOUR_API_KEY" } }
);
const data = await response.json();
// v2: results[] instead of reviews[], count instead of total_reviews
data.results.forEach(r => console.log(r.decision, r.reviewed_at));
console.log("Latest:", data.latest_decision);
Response Example
{
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"session_status": "completed",
"session_outcome": "clear",
"reviews": [
{
"review_id": "120e8400-e29b-41d4-a716-446655440012",
"decision": "approved",
"notes": "Identity verified successfully. All checks clear.",
"reviewed_by": {
"id": "130e8400-e29b-41d4-a716-446655440013",
"name": "Jane Smith",
"email": "jane.smith@company.com"
},
"reviewed_at": "2026-06-12T15:00:00Z",
"check_ids": null
}
],
"total_reviews": 1,
"latest_decision": "approved"
}
{
"count": 1,
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"session_status": "completed",
"session_outcome": "clear",
"latest_decision": "approved",
"results": [
{
"review_id": "120e8400-e29b-41d4-a716-446655440012",
"decision": "approved",
"notes": "Identity verified successfully. All checks clear.",
"reviewed_by": {
"id": "130e8400-e29b-41d4-a716-446655440013",
"name": "Jane Smith",
"email": "jane.smith@company.com"
},
"reviewed_at": "2026-06-12T15:00:00Z",
"check_ids": null
}
]
}
Webhook Events
The Verification API fires webhook notifications for key lifecycle events. Configure
a default webhook URL in your tenant settings, or pass webhook_url when creating a session.
All webhooks include an HMAC-SHA256 signature in the X-Webhook-Signature header.
Verify this signature using your webhook secret to ensure authenticity.
Event Types
| Event | Description |
|---|---|
verification.session_created | Fired immediately after session creation |
verification.session_accessed | Fired when user first opens verification link |
verification.session_completed | Fired when all checks complete |
verification.session_failed | Fired when verification fails |
verification.session_expired | Fired when verification link expires |
verification.check_completed | Fired for each individual check completion |
Webhook Payload (session_completed)
{
"event": "verification.session_completed",
"timestamp": "2026-06-12T12:15:00Z",
"data": {
"session_id": "770e8400-e29b-41d4-a716-446655440002",
"entity_id": "550e8400-e29b-41d4-a716-446655440000",
"entity_name": "John Doe",
"status": "completed",
"outcome": "clear",
"checks_completed": 2,
"completed_at": "2026-06-12T12:15:00Z",
"extracted_data": {
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1985-05-15",
"document_type": "passport",
"document_number": "P12345678"
}
}
}
Signature Verification (Python)
import hmac
import hashlib
def verify_webhook_signature(
payload_body: str,
signature_header: str,
webhook_secret: str,
) -> bool:
"""Verify webhook HMAC-SHA256 signature."""
expected = hmac.new(
webhook_secret.encode("utf-8"),
payload_body.encode("utf-8"),
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature_header, expected)
# In your webhook handler:
signature = request.headers.get("X-Webhook-Signature", "")
is_valid = verify_webhook_signature(
payload_body=request.body.decode("utf-8"),
signature_header=signature,
webhook_secret=YOUR_WEBHOOK_SECRET,
)
if not is_valid:
return HttpResponse(status=401) # Reject invalid signatures