Identity Verification (IDV) API
The Identity Verification API provides a single endpoint for submitting KYC (Know Your Customer) identity verification data. The API runs sanctions screening first, then verifies users through document verification and selfie matching.
Base URL
{{baseUrl}}/v2/idv/verify
Authentication
This API uses Basic Authentication. Include your merchant credentials in the Authorization header:
- Username:
{{merchantApiKey}} - Password:
{{merchantSecret}}
Processing Flow
- Validation — field formats, empty values, required fields (merchant-configured)
- Sanctions Screening — checks applicant against OpenSanctions database (threshold: 0.8)
- If unreachable → request blocked (fail closed)
- If matches found → request blocked, KYC skipped
- If no matches → proceed to KYC
- KYC Verification — document verification, face match, MRZ extraction, OCR comparison
- Logging — request, response, and uploaded files stored in database
- Webhook — summary POST sent to configured URL (if set)
Endpoint
POST /v2/idv/verify
Submit identity verification data with user information and identity documents.
Content-Type
multipart/form-data
Any field present in the request must have a non-empty value. Sending a field with an empty string will return a 400 error.
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
firstName | string | Yes | User's first name (English characters only) |
lastName | string | Yes | User's last name (English characters only) |
externalUserId | string | Yes | Unique identifier for the user in your system |
ocrMatch | string | No | Enable OCR name matching ("true" or "false"). Compares names on ID document against submitted names. |
middleName | string | No | User's middle name (English characters only) |
dob | string | No | Date of birth in YYYY-MM-DD format |
phone | string | No | Phone number in international format (e.g., +16045551234) |
email | string | No | Email address |
street | string | No | Street address line 1 (English characters only) |
street2 | string | No | Street address line 2 (English characters only) |
city | string | No | City (English characters only) |
state | string | No | State or province code (e.g., BC, ON) (English characters only) |
postcode | string | No | Postal or ZIP code |
country | string | No | Country code (ISO 3166-1 alpha-3, e.g., CAN, USA) |
nationality | string | No | Nationality code (ISO 3166-1 alpha-3) |
documentTypes | string | No | Comma-separated list: PASSPORT, DRIVERS, ID_CARD |
documentCountry | string | Conditional | Country code for issued documents (ISO 3166-1 alpha-3). Required when documentTypes is provided. |
ssn | string | Conditional | Social Security Number. Required when country is USA. |
Merchants can configure which optional fields are required via the portal's API Configuration page. When configured, the API enforces those fields as required and returns specific error messages listing which fields are missing.
File Upload Fields
All files: max 10 MB, formats JPEG, PNG, WEBP, BMP, PDF.
| Field | Type | Required When | Description |
|---|---|---|---|
passportFront | file | documentTypes includes PASSPORT | Front side of passport |
driversFront | file | documentTypes includes DRIVERS | Front side of driver's license |
driversBack | file | documentTypes includes DRIVERS | Back side of driver's license |
idCardFront | file | documentTypes includes ID_CARD | Front side of ID card |
idCardBack | file | documentTypes includes ID_CARD | Back side of ID card |
selfie | file | Any documentTypes provided | User selfie for face matching |
- Passport: Front side only — passports never require a back side
- Driver's License: Front + back required for most countries
- ID Card: Front + back required for most countries
- Selfie: Required when any document is provided, cannot be submitted alone
- Empty files: File fields must contain actual file data — empty file fields are rejected
Usage Examples
Example 1: Passport with OCR Match
curl -X POST '{{baseUrl}}/v2/idv/verify' \
-u '{{merchantApiKey}}:{{merchantSecret}}' \
-F 'firstName=Sophie' \
-F 'lastName=Gagnon' \
-F 'dob=1985-11-22' \
-F 'phone=+15145551234' \
-F 'email=sophie.gagnon@example.com' \
-F 'street=200 Rue Sainte-Catherine Ouest' \
-F 'city=Montreal' \
-F 'state=QC' \
-F 'postcode=H2X 1L1' \
-F 'country=CAN' \
-F 'nationality=CAN' \
-F 'documentTypes=PASSPORT' \
-F 'documentCountry=CAN' \
-F 'externalUserId=user-67890' \
-F 'ocrMatch=true' \
-F 'passportFront=@/path/to/passport.jpg' \
-F 'selfie=@/path/to/selfie.jpg'
Example 2: Driver's License (Canada)
curl -X POST '{{baseUrl}}/v2/idv/verify' \
-u '{{merchantApiKey}}:{{merchantSecret}}' \
-F 'firstName=Jordan' \
-F 'middleName=Robert' \
-F 'lastName=Tremblay' \
-F 'dob=1992-08-14' \
-F 'phone=+16045551234' \
-F 'email=jordan.tremblay@example.com' \
-F 'street=450 Granville Street' \
-F 'street2=Suite 200' \
-F 'city=Vancouver' \
-F 'state=BC' \
-F 'postcode=V6C 1V4' \
-F 'country=CAN' \
-F 'nationality=CAN' \
-F 'documentTypes=DRIVERS' \
-F 'documentCountry=CAN' \
-F 'externalUserId=user-12345' \
-F 'ocrMatch=true' \
-F 'driversFront=@/path/to/drivers_front.jpg' \
-F 'driversBack=@/path/to/drivers_back.jpg' \
-F 'selfie=@/path/to/selfie.jpg'
Example 3: Multiple Documents (Passport + Driver's License)
curl -X POST '{{baseUrl}}/v2/idv/verify' \
-u '{{merchantApiKey}}:{{merchantSecret}}' \
-F 'firstName=Luc' \
-F 'lastName=Pelletier' \
-F 'dob=1990-02-18' \
-F 'country=CAN' \
-F 'documentTypes=DRIVERS,PASSPORT' \
-F 'documentCountry=CAN' \
-F 'externalUserId=user-33333' \
-F 'ocrMatch=true' \
-F 'driversFront=@/path/to/drivers_front.jpg' \
-F 'driversBack=@/path/to/drivers_back.jpg' \
-F 'passportFront=@/path/to/passport.jpg' \
-F 'selfie=@/path/to/selfie.jpg'
Example 4: Minimal Required Fields
curl -X POST '{{baseUrl}}/v2/idv/verify' \
-u '{{merchantApiKey}}:{{merchantSecret}}' \
-F 'firstName=Akira' \
-F 'lastName=Tanaka' \
-F 'externalUserId=user-22222'
Response Format
All verification responses return HTTP 200. The success field in the response body indicates the outcome.
Success Response — Verification Passed
{
"success": true,
"metadata": {
"externalUserId": "user-67890",
"info": {
"firstName": "Sophie",
"lastName": "Gagnon",
"dob": "1985-11-22",
"country": "CAN"
},
"ocrMatch": true,
"documents": [
{ "idDocType": "PASSPORT", "country": "CAN" }
]
},
"documents_processed": 1,
"facemap_id": "69dd249e...",
"document_results": [
{
"document_type": "PASSPORT",
"face_match": true,
"similarity_score": 0.682,
"message": "Faces match"
}
],
"mrz_data": {
"mrz_data": {
"status": "SUCCESS",
"given_name": "SOPHIE",
"surname": "GAGNON",
"document_number": "AB1234567",
"issuer_code": "CAN",
"birth_date": "1985-11-22",
"expiry_date": "2034-11-23",
"sex": "F",
"mrz_type": "TD3"
},
"success": true
},
"ocr_comparison": {
"match": true,
"match_score": 100,
"field_results": {},
"mismatches": [],
"warnings": []
},
"kycResults": {
"status": 200,
"results": [],
"total": { "value": 0, "relation": "eq" }
}
}
Success Response — Sanctions Match Found (KYC Not Performed)
{
"success": false,
"message": "Sanctions screening failed — potential match found",
"kycResults": {
"status": 200,
"results": [
{
"id": "entity-id",
"caption": "Entity Name",
"schema": "Person",
"score": 0.85,
"match": true,
"datasets": ["us_ofac_sdn"]
}
],
"total": { "value": 1, "relation": "eq" }
}
}
Success Response — Sanctions Unavailable (KYC Not Performed)
{
"success": false,
"message": "Sanctions screening unavailable — unable to verify, please try again later",
"kycResults": { "error": "Sanctions check failed" }
}
Success Response — KYC Service Error
{
"success": false,
"message": "External verification service error",
"error": {
"code": "...",
"reason": "...",
"message": "..."
}
}
Error Responses
These errors return non-200 status codes and indicate the request was rejected before processing.
400 — Empty Field
{
"success": false,
"message": "Validation failed",
"errors": ["state cannot be empty"]
}
400 — Validation Error
{
"success": false,
"message": "Validation failed",
"errors": ["firstName - First name is required"]
}
400 — Missing Required Fields (Merchant Config)
{
"success": false,
"message": "Required fields missing",
"errors": [
"Date of Birth is required",
"Document Type is required: ID Card, Passport",
"ID Card Front is required",
"Passport Front is required",
"Selfie is required"
]
}
400 — File Validation Error
{
"success": false,
"message": "File validation failed",
"errors": ["selfie file is empty"]
}
400 — Missing SSN for US
{
"success": false,
"message": "Validation failed",
"errors": ["Social Security Number is mandatory for US citizens"]
}
401 — Invalid Credentials
{
"message": "Invalid Merchant or Secret Key"
}
403 — Restricted Jurisdiction
{
"success": false,
"message": "Restricted jurisdiction",
"errors": ["Country of residence 'RUS' is a restricted jurisdiction"]
}
The following countries are restricted and will return a 403 error:
- Russia (RUS)
- Additional restricted countries as configured by your compliance policy
Webhooks
Merchants can configure a webhook URL in the portal's API Configuration page. After each verification, a summary POST is sent to the configured URL.
Webhook Payload
{
"event": "idv.verification.completed",
"success": true,
"externalUserId": "user-67890",
"documentTypes": "PASSPORT",
"sanctionsMatch": 0,
"timestamp": "2026-04-16T12:00:00.000Z"
}
- Fire-and-forget — does not delay the API response
- Timeout: 10 seconds
- Disable: Leave webhook URL empty in the portal
Environment Variables
When using the Postman collection, configure these variables:
| Variable | Description | Example Value |
|---|---|---|
baseUrl | API base URL | http://localhost:3000 |
merchantApiKey | Your merchant API key | Provided in portal |
merchantSecret | Your merchant secret | Provided in portal |
Document Type Reference
| Document Type | Front Field | Back Field | Back Required |
|---|---|---|---|
| Passport | passportFront | N/A | Never |
| Driver's License | driversFront | driversBack | Most countries |
| ID Card | idCardFront | idCardBack | Most countries |
Country Code Reference
Common country codes (ISO 3166-1 alpha-3):
| Country | Code |
|---|---|
| Canada | CAN |
| United States | USA |
| United Kingdom | GBR |
| Australia | AUS |
| Germany | DEU |
| France | FRA |