POST /api/IdVerification/verify
Verify an identity document and match it against a selfie photo using facial recognition.
Endpoint
POST https://api.matchstra.ca/api/IdVerification/verify
Authentication
Requires API key in the X-API-Key header.
Request
Headers
| Header | Value | Required |
|---|---|---|
X-API-Key | Your API key | ✅ Yes |
Content-Type | multipart/form-data | ✅ Yes (set automatically by most HTTP clients) |
Body Parameters (Form Data)
| Parameter | Type | Required | Description |
|---|---|---|---|
IdCardImage | file | ✅ Yes | Government-issued ID document image (JPEG/PNG, max 10 MB) |
SelfieImage | file | ✅ Yes | Selfie photo of the person (JPEG/PNG, max 10 MB) |
Image Requirements
ID Card Image:
- Format: JPEG or PNG
- Max size: 10 MB
- Recommended: 1200×800 pixels or higher
- Must show: All text readable, all corners visible, no glare
Selfie Image:
- Format: JPEG or PNG
- Max size: 10 MB
- Recommended: 800×800 pixels or higher
- Must show: Face clearly visible, eyes open, no obstructions
Request Example
curl -X POST https://api.matchstra.ca/api/IdVerification/verify \
-H "X-API-Key: your_api_key_here" \
-F "IdCardImage=@/path/to/drivers-license.jpg" \
-F "SelfieImage=@/path/to/selfie.jpg"
// Browser JavaScript
const formData = new FormData();
formData.append('IdCardImage', idCardFile); // File object from <input type="file">
formData.append('SelfieImage', selfieFile);
const response = await fetch('https://api.matchstra.ca/api/IdVerification/verify', {
method: 'POST',
headers: {
'X-API-Key': 'your_api_key_here'
// Don't set Content-Type - browser will set it with boundary
},
body: formData
});
const data = await response.json();
using System.Net.Http;
using System.Net.Http.Headers;
var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-API-Key", "your_api_key_here");
using var formData = new MultipartFormDataContent();
// Add ID card image
var idCardContent = new ByteArrayContent(File.ReadAllBytes("drivers-license.jpg"));
idCardContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
formData.Add(idCardContent, "IdCardImage", "drivers-license.jpg");
// Add selfie image
var selfieContent = new ByteArrayContent(File.ReadAllBytes("selfie.jpg"));
selfieContent.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
formData.Add(selfieContent, "SelfieImage", "selfie.jpg");
var response = await client.PostAsync(
"https://api.matchstra.ca/api/IdVerification/verify",
formData
);
var result = await response.Content.ReadAsStringAsync();
Response
Success Response (200 OK)
Successful Match
{
"success": true,
"message": "Verification completed successfully",
"data": {
"id": 67890,
"faceMatch": true,
"matchConfidence": 96.8,
"livenessScore": 98.5,
"status": "Verified",
"extractedData": {
"documentType": "Driver License",
"documentNumber": "D1234567",
"fullName": "JANE MARY DOE",
"dateOfBirth": "1990-08-15T00:00:00Z",
"expiryDate": "2028-08-15T00:00:00Z",
"country": "Canada",
"region": "Ontario",
"address": "123 Main St, Toronto, ON M5V 1A1",
"nationality": "Canadian",
"sex": "F"
},
"remainingRequests": 234
},
"errors": null
}
No Match
{
"success": true,
"message": "Verification completed successfully",
"data": {
"id": 67891,
"faceMatch": false,
"matchConfidence": 42.3,
"livenessScore": 97.2,
"status": "Not Verified",
"extractedData": {
"documentType": "Driver License",
"documentNumber": "D1234567",
"fullName": "JANE MARY DOE",
"dateOfBirth": "1990-08-15T00:00:00Z",
"expiryDate": "2028-08-15T00:00:00Z",
"country": "Canada",
"region": "Ontario",
"address": "123 Main St, Toronto, ON M5V 1A1",
"nationality": "Canadian",
"sex": "F"
},
"remainingRequests": 233
},
"errors": null
}
Response Fields
| Field | Type | Description |
|---|---|---|
success | boolean | true if request succeeded |
message | string | Human-readable status message |
data | object | Verification result data |
data.id | integer | Unique verification ID |
data.faceMatch | boolean | true if face matches ID document |
data.matchConfidence | number | Face match confidence (0-100) |
data.livenessScore | number | Liveness detection score (0-100, or null) |
data.status | string | "Verified", "Not Verified", or "Manual Review Required" |
data.extractedData | object | Data extracted from ID document |
data.remainingRequests | integer | Remaining API quota |
errors | array | Error messages (null on success) |
Extracted Data Fields
| Field | Type | Description |
|---|---|---|
documentType | string | Type of document (e.g., "Driver License", "Passport") |
documentNumber | string | ID/document number |
fullName | string | Full name as on document |
dateOfBirth | string | Date of birth (ISO 8601) |
expiryDate | string | Document expiry date (ISO 8601) |
country | string | Issuing country |
region | string | State/province (if applicable) |
address | string | Address on document (if present) |
nationality | string | Nationality/citizenship |
sex | string | Gender marker ("M", "F", "X", etc.) |
note
Some extracted fields may be null if not present on the document or not readable by OCR.
Error Responses
400 Bad Request - Missing Files
{
"success": false,
"message": "Validation failed",
"data": null,
"errors": [
"IdCardImage is required",
"SelfieImage is required"
]
}
Cause: One or both image files missing from request.
400 Bad Request - Invalid Files
{
"success": false,
"message": "Invalid file upload",
"data": null,
"errors": [
"IdCardImage: File size exceeds 10 MB limit",
"SelfieImage: Invalid image format. Only JPEG and PNG are supported."
]
}
Causes:
- File size exceeds 10 MB
- Invalid file format (not JPEG/PNG)
- Corrupted image file
400 Bad Request - Poor Image Quality
{
"success": false,
"message": "Image quality insufficient",
"data": null,
"errors": [
"ID document text not readable - please retake with better lighting",
"No face detected in selfie image"
]
}
Causes:
- Image too blurry or low resolution
- Poor lighting
- ID document text not readable
- No face detected in selfie
- Multiple faces in selfie
401 Unauthorized
{
"success": false,
"message": "Unauthorized",
"data": null,
"errors": ["Invalid or missing API key"]
}
Cause: Invalid, missing, or revoked API key.
429 Too Many Requests
{
"success": false,
"message": "Rate limit exceeded",
"data": null,
"errors": ["Request quota exhausted"]
}
Cause: API quota limit reached.
Interpreting Results
Match Confidence Scores
| Score | Interpretation | Recommended Action |
|---|---|---|
| 90-100 | Very high confidence match | Auto-approve |
| 80-89 | High confidence match | Approve with standard review |
| 70-79 | Moderate confidence | Manual review recommended |
| 60-69 | Low confidence | Request better photos or manual review |
| 0-59 | Very low confidence / No match | Reject or request re-submission |
Liveness Scores
| Score | Interpretation | Risk |
|---|---|---|
| 90-100 | Very confident it's a live person | Very low spoof risk |
| 80-89 | Likely a live person | Low spoof risk |
| 70-79 | Uncertain | Moderate risk - review |
| 0-69 | Possible spoof (photo of photo, mask, etc.) | High risk - reject |
Status Values
- "Verified": Face matches and liveness checks passed
- "Not Verified": Face doesn't match or liveness check failed
- "Manual Review Required": Edge case requiring human review
Use Cases
Basic Verification
async function verifyIdentity(idCardFile, selfieFile) {
const formData = new FormData();
formData.append('IdCardImage', idCardFile);
formData.append('SelfieImage', selfieFile);
const response = await fetch('https://api.matchstra.ca/api/IdVerification/verify', {
method: 'POST',
headers: {
'X-API-Key': process.env.MATCHSTRA_API_KEY
},
body: formData
});
const result = await response.json();
if (result.success && result.data.faceMatch) {
console.log('✅ Identity verified!');
return result.data;
} else {
console.log('❌ Verification failed');
return null;
}
}
Decision Logic
function makeVerificationDecision(verificationData) {
// Check face match
if (!verificationData.faceMatch) {
return { approved: false, reason: 'Face does not match ID' };
}
// Check match confidence
if (verificationData.matchConfidence < 75) {
return { approved: false, reason: 'Match confidence too low' };
}
// Check liveness
if (verificationData.livenessScore !== null && verificationData.livenessScore < 70) {
return { approved: false, reason: 'Possible spoof attempt' };
}
// Check document expiry
const expiryDate = new Date(verificationData.extractedData.expiryDate);
if (expiryDate < new Date()) {
return { approved: false, reason: 'ID document expired' };
}
return { approved: true, reason: 'All checks passed' };
}
// Usage
const verification = await verifyIdentity(idCard, selfie);
const decision = makeVerificationDecision(verification);
if (decision.approved) {
createAccount(verification.extractedData);
} else {
rejectApplication(decision.reason);
}
Notes
- Processing time: Average 3-6 seconds
- Supported documents: Passports, driver's licenses, national ID cards, residence permits
- Countries: 150+ countries supported
- Storage: Images are stored securely for 90 days for audit purposes, then deleted
- Privacy: Complies with GDPR, PIPEDA, and CCPA
Related Endpoints
- GET /api/IdVerification/list - List all verifications
- GET /api/IdVerification/{id} - Get specific verification
See Also
- ID Verification Guide - Comprehensive guide with best practices
- Error Handling - Handle errors gracefully
- Rate Limits - Manage API quota