Skip to main content
POST
/
kyc
/
facematch
Face Matching
curl --request POST \
  --url https://api.example.com/kyc/facematch
Biometric face matching API for identity verification using AWS Rekognition. Supports 1:1 face verification, 1:N face search, face registration, and blacklist management.

Overview

The Face Matching API provides comprehensive biometric verification capabilities:
  • 1:1 Verification: Compare two face images to verify identity
  • 1:N Search: Search for a face in the registered collection
  • Face Registration: Register faces in tenant-specific collections
  • Blacklist Management: Flag faces for fraud prevention
  • Presigned Uploads: Secure direct-to-S3 image uploads
Face matching must be enabled for your tenant. Contact support to enable this feature.

Endpoints

EndpointMethodDescription
/kyc/facematch/verifyPOST1:1 face verification
/kyc/facematch/registerPOSTRegister face in collection
/kyc/facematch/searchPOST1:N face search
/kyc/facematch/blacklistPOSTAdd face to blacklist
/kyc/facematch/faces/{face_id}DELETEDelete face from collection
/kyc/facematch/collections/statusGETGet collection status
/kyc/facematch/upload-urlPOSTGenerate presigned upload URL

Authentication

All endpoints require Bearer token authentication. Required permissions vary by endpoint:
EndpointRequired Permission
Verifykyc:read
Registerkyc:create
Searchkyc:read
Blacklistkyc:create
Deletekyc:create
Collection Statuskyc:read
Upload URLkyc:create

1:1 Face Verification

Compare two face images to determine if they belong to the same person.
POST /kyc/facematch/verify

Request Parameters

Request Example

curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/verify \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_image": "base64_encoded_image...",
    "target_image": "base64_encoded_image...",
    "threshold": 0.7,
    "image_format": "base64"
  }'

Using S3 Images

curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/verify \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_image": "s3://bucket-name/path/to/source.jpg",
    "target_image": "s3://bucket-name/path/to/target.jpg",
    "image_format": "s3"
  }'

Response

{
  "status": "success",
  "data": {
    "is_match": true,
    "similarity_score": 0.9523,
    "confidence": 0.8765,
    "processing_time_ms": 1250
  }
}

Response Fields

FieldTypeDescription
is_matchbooleanWhether faces match (similarity >= threshold)
similarity_scorenumberSimilarity score (0.0-1.0)
confidencenumberConfidence level of the comparison (0.0-1.0)
processing_time_msintegerProcessing time in milliseconds

Face Registration

Register a face in the tenant’s collection for future searches.
POST /kyc/facematch/register

Request Parameters

Request Example

curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/register \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "base64_encoded_image...",
    "session_id": "sess_123456",
    "metadata": {
      "full_name": "John Doe",
      "document_type": "passport"
    },
    "is_reference": true,
    "image_format": "base64"
  }'

Response

{
  "status": "success",
  "data": {
    "face_id": "face_abc123def456",
    "rekognition_face_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "s3_key": "faces/tenant_123/sess_123456/face_abc123def456.jpg",
    "message": "Face registered successfully"
  }
}

Response Fields

FieldTypeDescription
face_idstringUnique face identifier
rekognition_face_idstringAWS Rekognition face ID
s3_keystringS3 key where face image is stored
messagestringSuccess message

Search for a face across all registered faces in the tenant’s collection.
POST /kyc/facematch/search

Request Parameters

Request Example

curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/search \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "image": "base64_encoded_image...",
    "max_results": 5,
    "threshold": 0.85,
    "image_format": "base64"
  }'

Response

{
  "status": "success",
  "data": {
    "matches": [
      {
        "face_id": "face_abc123def456",
        "session_id": "sess_123456",
        "similarity": 0.9876,
        "metadata": {
          "full_name": "John Doe",
          "document_type": "passport"
        },
        "is_blacklisted": false
      },
      {
        "face_id": "face_xyz789ghi012",
        "session_id": "sess_789012",
        "similarity": 0.8532,
        "metadata": {},
        "is_blacklisted": true,
        "blacklist_reason": "Suspected fraud"
      }
    ],
    "total_matches": 2,
    "search_time_ms": 850
  }
}

Response Fields

FieldTypeDescription
matchesarrayList of matching faces
total_matchesintegerTotal number of matches found
search_time_msintegerSearch time in milliseconds

Match Fields

FieldTypeDescription
face_idstringUnique face identifier
session_idstringAssociated KYC session ID
similaritynumberSimilarity score (0.0-1.0)
metadataobjectStored metadata
is_blacklistedbooleanWhether face is blacklisted
blacklist_reasonstringReason for blacklisting (if applicable)
Blacklisted faces are included in search results (marked with is_blacklisted: true) to alert you when a flagged person is detected.

Add to Blacklist

Mark a registered face as blacklisted for fraud prevention.
POST /kyc/facematch/blacklist

Request Parameters

Request Example

curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/blacklist \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "face_id": "face_abc123def456",
    "reason": "Suspected identity fraud"
  }'

Response

{
  "status": "success",
  "data": {
    "message": "Face blacklisted successfully"
  }
}

Delete Face

Remove a registered face from the collection.
DELETE /kyc/facematch/faces/{face_id}

Path Parameters

ParameterTypeDescription
face_idstringFace ID to delete

Request Example

curl -X DELETE https://stg.kyc.legaltalent.ai/kyc/facematch/faces/face_abc123def456 \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

{
  "status": "success",
  "data": {
    "message": "Face deleted successfully"
  }
}

Collection Status

Get status information about the tenant’s face collection.
GET /kyc/facematch/collections/status

Request Example

curl -X GET https://stg.kyc.legaltalent.ai/kyc/facematch/collections/status \
  -H "Authorization: Bearer YOUR_TOKEN"

Response

{
  "status": "success",
  "data": {
    "collection_name": "kyc-faces-tenant_123-prod",
    "face_count": 1542,
    "status": "ACTIVE"
  }
}

Response Fields

FieldTypeDescription
collection_namestringAWS Rekognition collection name
face_countintegerNumber of registered faces
statusstringCollection status (ACTIVE, CREATING, etc.)

Generate Upload URL

Generate a presigned URL for direct S3 image upload.
POST /kyc/facematch/upload-url

Request Parameters

Request Example

curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/upload-url \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "sess_123456",
    "expires_in": 900
  }'

Response

{
  "status": "success",
  "data": {
    "upload_url": "https://bucket.s3.amazonaws.com/path?...",
    "s3_uri": "s3://bucket-name/faces/tenant_123/sess_123456/uuid.jpg",
    "s3_key": "faces/tenant_123/sess_123456/uuid.jpg",
    "expires_at": 1732281600
  }
}

Response Fields

FieldTypeDescription
upload_urlstringPresigned URL for uploading
s3_uristringS3 URI for use in other endpoints
s3_keystringS3 key where image will be stored
expires_atintegerUnix timestamp when URL expires

Upload Workflow

  1. Request a presigned upload URL
  2. Upload image directly to S3 using the presigned URL
  3. Use the returned s3_uri in register/verify/search endpoints with image_format: "s3"
# Step 1: Get upload URL
UPLOAD_RESPONSE=$(curl -s -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/upload-url \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"session_id": "sess_123"}')

UPLOAD_URL=$(echo $UPLOAD_RESPONSE | jq -r '.data.upload_url')
S3_URI=$(echo $UPLOAD_RESPONSE | jq -r '.data.s3_uri')

# Step 2: Upload image to S3
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: image/jpeg" \
  --data-binary @photo.jpg

# Step 3: Use S3 URI in verification
curl -X POST https://stg.kyc.legaltalent.ai/kyc/facematch/verify \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"source_image\": \"$S3_URI\",
    \"target_image\": \"$S3_URI_2\",
    \"image_format\": \"s3\"
  }"

Error Responses

400 Bad Request

{
  "status": "error",
  "error": "Invalid input: source_image is required"
}

403 Forbidden - Feature Not Enabled

{
  "status": "error",
  "error": "Face matching is not enabled for this tenant"
}

403 Forbidden - Permission Denied

{
  "status": "error",
  "error": "Permission denied. Required: kyc:create"
}

404 Not Found

{
  "status": "error",
  "error": "Face not found"
}

400 Bad Request - No Face Detected

{
  "status": "error",
  "error": "No face detected in one or both images"
}

400 Bad Request - Max Faces Exceeded

{
  "status": "error",
  "error": "Maximum 5 faces allowed per session"
}

Status Codes

CodeDescription
200Success
201Created (registration)
400Bad Request - Invalid parameters
401Unauthorized - Missing or invalid token
403Forbidden - Feature not enabled or insufficient permissions
404Not Found - Face not found
500Internal Server Error

Usage Examples

Python Example - Complete Verification Flow

import requests
import base64

BASE_URL = "https://stg.kyc.legaltalent.ai"
TOKEN = "YOUR_TOKEN"

headers = {
    "Authorization": f"Bearer {TOKEN}",
    "Content-Type": "application/json"
}

def encode_image(file_path):
    """Encode image file to base64."""
    with open(file_path, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")

def verify_faces(source_path, target_path, threshold=0.7):
    """Verify if two face images match."""
    response = requests.post(
        f"{BASE_URL}/kyc/facematch/verify",
        headers=headers,
        json={
            "source_image": encode_image(source_path),
            "target_image": encode_image(target_path),
            "threshold": threshold,
            "image_format": "base64"
        }
    )
    return response.json()

def register_face(image_path, session_id, metadata=None):
    """Register a face in the collection."""
    response = requests.post(
        f"{BASE_URL}/kyc/facematch/register",
        headers=headers,
        json={
            "image": encode_image(image_path),
            "session_id": session_id,
            "metadata": metadata or {},
            "image_format": "base64"
        }
    )
    return response.json()

def search_face(image_path, threshold=0.8, max_results=10):
    """Search for matching faces in collection."""
    response = requests.post(
        f"{BASE_URL}/kyc/facematch/search",
        headers=headers,
        json={
            "image": encode_image(image_path),
            "threshold": threshold,
            "max_results": max_results,
            "image_format": "base64"
        }
    )
    return response.json()

# Example usage
if __name__ == "__main__":
    # 1:1 Verification
    result = verify_faces("id_photo.jpg", "selfie.jpg", threshold=0.7)
    print(f"Match: {result['data']['is_match']}")
    print(f"Similarity: {result['data']['similarity_score']}")
    
    # Register face
    register_result = register_face(
        "id_photo.jpg",
        "sess_123456",
        metadata={"full_name": "John Doe", "document_type": "passport"}
    )
    print(f"Face ID: {register_result['data']['face_id']}")
    
    # Search for face
    search_result = search_face("new_photo.jpg", threshold=0.85)
    print(f"Found {search_result['data']['total_matches']} matches")
    
    for match in search_result['data']['matches']:
        if match['is_blacklisted']:
            print(f"⚠️ BLACKLISTED: {match['face_id']} - {match['blacklist_reason']}")
        else:
            print(f"Match: {match['face_id']} ({match['similarity']:.2%})")

JavaScript Example

const BASE_URL = 'https://stg.kyc.legaltalent.ai';
const TOKEN = 'YOUR_TOKEN';

const headers = {
  'Authorization': `Bearer ${TOKEN}`,
  'Content-Type': 'application/json'
};

async function verifyFaces(sourceBase64, targetBase64, threshold = 0.7) {
  const response = await fetch(`${BASE_URL}/kyc/facematch/verify`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      source_image: sourceBase64,
      target_image: targetBase64,
      threshold,
      image_format: 'base64'
    })
  });
  return response.json();
}

async function searchFace(imageBase64, threshold = 0.8, maxResults = 10) {
  const response = await fetch(`${BASE_URL}/kyc/facematch/search`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      image: imageBase64,
      threshold,
      max_results: maxResults,
      image_format: 'base64'
    })
  });
  return response.json();
}

// Example: File input handler
async function handleFileUpload(idFile, selfieFile) {
  const toBase64 = file => new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result.split(',')[1]);
    reader.onerror = reject;
  });
  
  const idBase64 = await toBase64(idFile);
  const selfieBase64 = await toBase64(selfieFile);
  
  const result = await verifyFaces(idBase64, selfieBase64);
  
  if (result.data.is_match) {
    console.log(`✅ Face verified! Similarity: ${(result.data.similarity_score * 100).toFixed(1)}%`);
  } else {
    console.log(`❌ Face mismatch. Similarity: ${(result.data.similarity_score * 100).toFixed(1)}%`);
  }
  
  return result;
}

Tenant Configuration

Face matching behavior is configured per tenant:
SettingDefaultDescription
enabledfalseWhether face matching is enabled
verification_threshold0.6Default threshold for 1:1 verification
search_threshold0.8Default threshold for 1:N search
max_faces_per_user5Maximum faces per session
enable_blacklisttrueEnable blacklist functionality
model_versionRekognitionFace detection model
Contact support to modify these settings for your tenant.

Best Practices

Image Quality

  • Use high-quality images (minimum 640x480 pixels)
  • Ensure good lighting with face clearly visible
  • Avoid heavily compressed images
  • Face should occupy at least 20% of the image

Security

  • Use presigned URLs for large images to avoid base64 overhead
  • Store face IDs securely - they link to biometric data
  • Implement rate limiting on verification endpoints
  • Review blacklist matches with human oversight

Performance

  • Use S3 image format for large images (>1MB)
  • Keep max_results reasonable in searches
  • Cache collection status if needed frequently
  • Batch registrations when onboarding multiple users

Compliance

  • Inform users about biometric data collection
  • Implement data retention policies
  • Provide mechanism for users to request data deletion
  • Log all face matching operations for audit trails