system-design46 min read

How to Design an Identity Verification & KYC Platform — A Senior+ Guide | Ayodhyya

How to Design an Identity Verification & KYC Platform

Building a Production-Grade Know Your Customer Engine — Document Verification, Biometrics, AML Compliance

Senior+ System Design Guide 10,000+ Words 25 Deep-Dive Sections C# · Mermaid · Real-World Case Studies

1. Introduction & Why KYC is Hard

Identity verification is the backbone of trust in the digital economy. Every time a user opens a bank account, applies for a loan, purchases cryptocurrency, or registers on a regulated platform, the provider must verify that the person is who they claim to be — and that they are not involved in money laundering, terrorism financing, or fraud. This process, broadly called Know Your Customer (KYC), is legally mandated in over 190 countries under anti-money laundering (AML) regulations enforced by bodies like the Financial Action Task Force (FATF), FinCEN (US), the FCA (UK), and the EU's AMLD directives. Failure to comply can result in fines exceeding $1 billion — as seen with HSBC's $1.9 billion settlement in 2012 or Westpac's $1.3 billion penalty in 2020.

Building a KYC platform is not just a compliance checkbox — it is a complex engineering challenge spanning computer vision, machine learning, distributed systems, document forensics, and regulatory technology. The system must verify government-issued identity documents from over 195 countries (each with unique layouts, security features, and languages), detect sophisticated fraud attempts (Photoshopped documents, deepfake videos, printed screen captures), perform real-time biometric matching between a selfie and an ID photo, screen individuals against global sanctions lists (OFAC, UN, EU), calculate AML risk scores, and do all of this in under 30 seconds while meeting strict data privacy regulations (GDPR, CCPA, PIPL). The platform must be accurate (false rejection rates below 2% for legitimate users), fast (under 30 seconds for 90% of verifications), and secure (biometric data encrypted at rest with AES-256 and in transit with TLS 1.3).

Key Insight: A KYC platform is not a single verification — it is an orchestrated pipeline of independent checks (document authenticity, biometric match, liveness, watchlist, AML risk) that each produce a confidence score. The platform's job is to combine these signals into a final accept/reject/escalate decision, balancing false acceptance (letting a fraudster through) against false rejection (turning away a legitimate customer). The optimal operating point depends on the client's risk appetite and regulatory requirements.

The complexity deepens when you consider the global nature of identity. A passport from Japan looks nothing like one from Nigeria. A driver's license from Germany has different security features than one from Brazil. Some countries use biometric passports with RFID chips, others use paper laminated cards. Some IDs have MRZ (Machine Readable Zone) codes, others have QR codes, and some have neither. The platform must handle all of these variations while maintaining consistent accuracy and speed. Additionally, fraudsters constantly evolve their techniques — from simple Photoshop edits to sophisticated AI-generated deepfakes and forged holograms — requiring the platform to continuously update its fraud detection models.

Real-world KYC platforms operate at massive scale. Jumio, a leading identity verification provider, processes over 1 million verification attempts per day across 200+ countries. Onfido handles 20 million checks per month for companies like Revolut and Zipcar. Stripe Identity processes verifications for millions of businesses on the Stripe platform. These platforms must maintain sub-30-second response times, 99.9%+ uptime, and sub-1% false rejection rates while scaling to handle traffic spikes (such as a crypto exchange during a bull market). Building such a platform requires careful engineering across every layer of the stack, from the mobile SDK that captures the document photo to the ML pipeline that analyzes it to the compliance engine that makes the final decision.

Real-World Case Studies

CompanySystemScaleKey Innovation
JumioIdentity verification platform1M+ checks/dayAI-powered document + biometric verification, liveness detection
OnfidoIdentity verification SDK20M checks/monthFacial biometrics with ML, smartphone-based document scanning
Stripe IdentityEmbedded verificationMillions of businessesAPI-first design, pre-built UI components, multi-document support
TruliooGlobal identity verification5B+ data points500+ data sources across 100+ countries, real-time database checks
SumsubVerification & AML platformMillions of usersCombined KYC + AML + transaction monitoring, modular API

Jumio's approach is particularly instructive: they combine document verification (analyzing the physical document for authenticity), biometric verification (matching the user's face to the document photo), and liveness detection (ensuring the user is physically present, not a photo or video replay) into a single orchestrated flow. Their key innovation is the "identity cube" — a 3D model of the document constructed from multiple images to detect thickness anomalies, lamination issues, and other physical tampering indicators.

Onfido pioneered the concept of "smart document capture" — using the smartphone's camera with real-time ML guidance to ensure the user captures a high-quality image of their document. The SDK provides feedback like "move closer", "reduce glare", "center the document" to optimize the capture quality before it's even sent to the server. This dramatically improves the first-attempt success rate and reduces the need for manual review.

2. Functional & Non-Functional Requirements

Functional Requirements

  1. Document Verification: Accept and verify government-issued identity documents (passports, national ID cards, driver's licenses) from 190+ countries. Extract text data via OCR and verify document authenticity using AI models.
  2. Biometric Verification: Capture a live selfie from the user and match it against the photo on their identity document using face recognition models. Support liveness detection to prevent spoofing attacks.
  3. Watchlist Screening: Screen individuals against global sanctions lists (OFAC SDN, UN Security Council, EU Consolidated List), Politically Exposed Persons (PEP) databases, and adverse media sources.
  4. AML Risk Scoring: Calculate a composite risk score based on document authenticity, biometric match confidence, watchlist matches, address risk, and country risk factors.
  5. KYC Workflow Orchestration: Manage the end-to-end verification workflow from document collection through verification to final approval/rejection, with manual review queues for edge cases.
  6. Ongoing Monitoring: Re-verify customers periodically and when risk indicators change. Monitor for document expiry, new sanctions matches, and adverse media.
  7. Multi-Tenant SDK: Provide embeddable JavaScript and mobile SDKs for web and native app integration with customizable UI.

Non-Functional Requirements

RequirementTargetRationale
Verification Latency (automated)< 30 seconds for 90% of attemptsUser experience — long waits cause abandonment
False Accept Rate (FAR)< 0.1%Regulatory requirement — never let a fraudster through
False Rejection Rate (FRR)< 2%Revenue impact — legitimate users must not be blocked
Liveness Detection Accuracy> 99% attack detectionCritical for preventing spoofing attacks
Document Coverage190+ countries, 10,000+ document typesGlobal platform must handle diverse identity documents
Availability99.99%Downtime blocks customer onboarding
Data EncryptionAES-256 at rest, TLS 1.3 in transitBiometric data requires highest security standards
Data RetentionConfigurable per jurisdiction (default 5 years)AML regulations require 5-year record retention
Manual Review SLA< 4 hours for escalationsCustomers should not wait more than 4 hours
API Rate Limit1000 req/min per clientProtect platform from abuse
GDPR ComplianceRight to erasure within 72 hoursEuropean data protection requirement
SOC 2 Type IIAnnual auditEnterprise customer requirement

Key Design Tradeoffs

TradeoffOption AOption BOur Choice
On-device vs Server-sideOn-device (faster, privacy-friendly, limited accuracy)Server-side (higher accuracy, higher latency)Hybrid — on-device capture guidance + server-side ML
Synchronous vs AsyncSynchronous (simpler, user waits)Async (better UX, complex callback handling)Async with webhook callbacks + polling
Custom ML vs Third-party APICustom ML (full control, high upfront cost)Third-party API (fast to market, ongoing cost)Third-party for core (Jumio/Onfido), custom for niche
Single database vs Multi-regionSingle region (simpler, GDPR issues)Multi-region (compliant, complex)Multi-region with data residency controls

3. High-Level Architecture Overview

The identity verification platform consists of seven main components: the Client SDK (captures documents and selfies), the API Gateway (routes requests and enforces rate limits), the Verification Engine (orchestrates the multi-step verification pipeline), the ML Services (document analysis, face matching, liveness detection), the Compliance Engine (watchlist screening, AML risk scoring), the Review Dashboard (manual review queue for edge cases), and the Data Store (encrypted document images, verification results, audit logs). These components communicate through an event-driven architecture using Kafka for asynchronous processing and gRPC for synchronous ML inference calls.

graph TB subgraph Client["Client Layer"] WebSDK["Web SDK (JavaScript)"] MobileSDK["Mobile SDK (iOS/Android)"] API["REST API"] end subgraph Gateway["API Gateway"] Auth["Authentication"] RateLimit["Rate Limiter"] Router["Request Router"] end subgraph Verification["Verification Engine"] Orchestrator["Pipeline Orchestrator"] WorkflowEngine["Workflow State Machine"] DecisionEngine["Decision Engine"] end subgraph ML["ML Services"] OCR["OCR Service"] FaceMatch["Face Matching"] Liveness["Liveness Detection"] FraudDetect["Fraud Detection"] end subgraph Compliance["Compliance Engine"] Watchlist["Watchlist Screening"] AML["AML Risk Scoring"] Addr["Address Verification"] end subgraph Review["Manual Review"] Dashboard["Review Dashboard"] Queue["Review Queue"] end subgraph Storage["Storage Layer"] S3["S3 (Encrypted Images)"] PG["PostgreSQL"] Redis["Redis"] Kafka["Kafka"] end WebSDK --> Auth MobileSDK --> Auth API --> Auth Auth --> RateLimit RateLimit --> Router Router --> Orchestrator Orchestrator --> OCR Orchestrator --> FaceMatch Orchestrator --> Liveness Orchestrator --> FraudDetect Orchestrator --> Watchlist Orchestrator --> AML Orchestrator --> DecisionEngine OCR --> S3 DecisionEngine --> Queue Queue --> Dashboard Orchestrator --> PG Orchestrator --> Kafka Orchestrator --> Redis

Request Flow: End-to-End Verification

  1. Capture: The client SDK guides the user through document capture (auto-crop, glare detection, focus quality check) and selfie capture (face positioning, initial liveness check). Captured images are compressed client-side and uploaded directly to S3 via pre-signed URLs.
  2. Document Analysis: The OCR service extracts text from the document (name, DOB, document number, expiry, MRZ data). The fraud detection service analyzes the image for signs of tampering (pixel manipulation, inconsistent fonts, missing security features).
  3. Biometric Verification: The face matching service compares the selfie against the ID photo using deep learning models (achieving 99.5%+ accuracy). The liveness service ensures the selfie is from a live person, not a photo, screen, mask, or deepfake video.
  4. Compliance Checks: The watchlist service screens the individual's name and DOB against OFAC, UN, EU, and PEP databases. The AML service calculates a risk score incorporating document authenticity, biometric confidence, watchlist matches, country risk, and address risk.
  5. Decision: The decision engine combines all verification signals to produce a final result: APPROVED, REJECTED, or ESCALATED (requires manual review). The customer is notified via webhook callback.

4. Document Verification (Passport, Driver's License, ID Card)

Document verification is the foundation of KYC — it confirms that the identity document presented is genuine, not forged, and belongs to the person presenting it. Each document type has unique characteristics, security features, and verification approaches. The platform must handle over 10,000 document types from 190+ countries, each with different layouts, languages, scripts, and security features.

Document Types & Security Features

Document TypeKey FieldsSecurity FeaturesVerification Method
PassportName, DOB, nationality, photo, passport number, expiryMRZ, hologram, RFID chip, UV features, microprintMRZ validation + hologram analysis + chip read
Driver's LicenseName, DOB, address, photo, license number, vehicle classHologram, UV overlay, microprint, guilloche patternsLayout analysis + hologram detection + UV check
National ID CardName, DOB, address, photo, national ID numberHologram, RFID chip, UV features, tactile elementsChip read (if available) + visual analysis

MRZ Validation

The Machine Readable Zone (MRZ) is present on passports and some ID cards. It encodes the holder's name, document number, nationality, date of birth, and sex in a standardized format with checksums. MRZ validation is the first and most reliable check — if the MRZ checksums fail, the document is almost certainly forged or corrupted.

C#
public class MrzValidator
{
    public MrzValidationResult Validate(string mrzLine1, string mrzLine2)
    {
        var result = new MrzValidationResult();

        // Validate document number checksum
        var docNumber = mrzLine2.Substring(0, 9).TrimEnd('<');
        var docChecksum = int.Parse(mrzLine2[9].ToString());
        var calculatedChecksum = CalculateMrzChecksum(mrzLine2.Substring(0, 9));
        result.DocumentNumberValid = docChecksum == calculatedChecksum;

        // Validate date of birth checksum
        var dob = mrzLine2.Substring(13, 6);
        var dobChecksum = int.Parse(mrzLine2[19].ToString());
        result.DateOfBirthValid = dobChecksum ==
            CalculateMrzChecksum(mrzLine2.Substring(13, 6));

        // Validate expiry date checksum
        var expiry = mrzLine2.Substring(21, 6);
        var expiryChecksum = int.Parse(mrzLine2[27].ToString());
        result.ExpiryValid = expiryChecksum ==
            CalculateMrzChecksum(mrzLine2.Substring(21, 6));

        // Validate composite checksum
        var composite = mrzLine2.Substring(0, 7) +
            mrzLine2.Substring(8, 7) + mrzLine2.Substring(15, 7) +
            mrzLine2.Substring(22, 7) + mrzLine2.Substring(31, 7);
        var compositeChecksum = int.Parse(mrzLine2[36].ToString());
        result.CompositeValid = compositeChecksum ==
            CalculateMrzChecksum(composite);

        result.IsValid = result.DocumentNumberValid &&
            result.DateOfBirthValid && result.ExpiryValid &&
            result.CompositeValid;

        return result;
    }

    private static int CalculateMrzChecksum(string data)
    {
        int[] weights = { 7, 3, 1 };
        int sum = 0;
        for (int i = 0; i < data.Length; i++)
        {
            int value = char.IsDigit(data[i])
                ? data[i] - '0'
                : GetLetterValue(data[i]);
            sum += value * weights[i % 3];
        }
        return sum % 10;
    }

    private static int GetLetterValue(char c) => c switch
    {
        '<' => 0,
        _ when c >= 'A' && c <= 'Z' => c - 'A' + 10,
        _ => 0
    };
}

Document Authenticity Analysis

Beyond MRZ validation, the platform performs multi-layered document analysis to detect forgery. The analysis pipeline examines four dimensions: visual consistency (fonts, alignment, layout), security features (holograms, UV patterns, microprint), material properties (thickness, reflectivity, edge profile), and digital forensics (image manipulation, JPEG artifacts, inconsistent lighting).

graph LR A["Document Image"] --> B["Preprocessing"] B --> C["Layout Analysis"] B --> D["MRZ Extraction"] B --> E["Security Feature Detection"] C --> F["Template Matching"] D --> G["MRZ Validation"] E --> H["Hologram Detection"] E --> I["UV Analysis"] F --> K["Authenticity Score"] G --> K H --> K I --> K K --> L["Decision: Genuine / Suspicious / Forged"]

Each document type has a template that defines the expected layout — where the photo should be, where text fields are positioned, where security features are located. The platform maintains a database of over 10,000 document templates covering 190+ countries. Template matching compares the captured document against the expected template to detect anomalies like moved text fields, replaced photos, or missing security features.

Template Database Maintenance: Governments regularly update their identity documents — new security features, layout changes, format updates. The platform must maintain a dedicated team that monitors document updates across 190+ countries and updates templates accordingly. A template that is even 6 months out of date may reject genuine documents or fail to detect forgeries based on the new format.

5. OCR & Data Extraction Pipeline

Optical Character Recognition transforms the captured document image into structured data that the verification engine can process. The OCR pipeline must handle diverse document types, languages (Latin, Cyrillic, CJK, Arabic, Devanagari scripts), fonts, orientations, and image quality conditions (glare, shadow, blur, partial occlusion).

OCR Pipeline Architecture

graph TB A["Raw Document Image"] --> B["Image Preprocessing"] B --> C["Orientation Detection"] C --> D["Document Region Detection"] D --> E["Perspective Correction"] E --> F["Zone Segmentation"] F --> G["MRZ Zone"] F --> H["Photo Zone"] F --> I["Text Zones"] G --> K["MRZ Parser"] H --> L["Photo Extractor"] I --> M["OCR Engine"] M --> N["Field Extractor"] N --> O["Structured Output (JSON)"]

Image Preprocessing

Raw images from smartphone cameras are rarely optimal for OCR. The preprocessing stage normalizes the image: grayscale conversion, contrast enhancement (CLAHE), noise reduction (bilateral filtering), binarization (adaptive thresholding), and deskewing (correcting rotation). For documents with glare, the system detects the glare region and attempts to recover the underlying text using multi-exposure fusion.

C#
public class DocumentImagePreprocessor
{
    public PreprocessedImage Preprocess(byte[] rawImage)
    {
        using var image = Image.Load<Rgba32>(rawImage);

        // Step 1: Detect document region and crop
        var documentRegion = DetectDocumentRegion(image);
        var cropped = image.Clone(x =>
            x.Crop(documentRegion.BoundingRect));

        // Step 2: Correct perspective distortion
        var corrected = PerspectiveCorrect(cropped,
            documentRegion.Corners);

        // Step 3: Normalize orientation
        var orientation = DetectOrientation(corrected);
        if (orientation != Orientation.Normal)
            corrected = RotateImage(corrected, orientation);

        // Step 4: Enhance for OCR
        var enhanced = EnhanceForOcr(corrected);

        // Step 5: Detect and handle glare
        var glareRegions = DetectGlare(enhanced);
        if (glareRegions.Any())
            enhanced = ReduceGlare(enhanced, glareRegions);

        return new PreprocessedImage
        {
            Image = enhanced,
            QualityScore = CalculateQualityScore(enhanced),
            GlareDetected = glareRegions.Any()
        };
    }
}

Field Extraction & Standardization

After OCR produces raw text for each zone, the field extractor maps the text to a standardized schema. Different countries use different field names, label formats, and data structures. For example, "Date of Birth" might appear as "DOB", "Date de naissance", "Geburtsdatum", or "出生日期". The field extractor uses zone position, label matching (fuzzy string matching), and ML classification to map fields regardless of language.

OCR Accuracy Benchmarking: The OCR pipeline is benchmarked against a labeled dataset of 100,000 document images spanning 200+ document types. Target: field-level extraction accuracy of 98%+ for machine-readable documents and 95%+ for non-MRZ documents. Character error rate must be below 1% for MRZ zones and below 3% for printed text zones.

6. Liveness Detection (3D Depth, Challenge-Response)

Liveness detection is the critical defense against spoofing attacks where an attacker presents a photo, video, mask, or deepfake instead of their real face. The three main approaches are passive liveness (no user interaction required), active liveness (user performs challenges), and 3D depth analysis (using structured light or time-of-flight sensors).

Attack Vectors & Countermeasures

Attack TypeDescriptionDetection MethodAccuracy
Photo AttackUser holds up a printed photo or displays on another screenTexture analysis, Moiré pattern detection, depth check99.5%
Video ReplayUser plays a video of the target personTemporal consistency, blink detection, screen artifact detection99.2%
3D MaskUser wears a realistic silicone or 3D-printed mask3D depth analysis, IR reflection, skin texture analysis98.8%
DeepfakeAI-generated video of the target personGAN artifact detection, temporal consistency, eye tracking98.5%
Digital OverlayDigital face overlaid on captured videoEdge consistency, lighting analysis, depth mismatch99.0%

Passive Liveness Detection

Passive liveness detection analyzes the selfie image or video stream without requiring the user to perform any specific action. The passive liveness model examines: texture patterns (real skin has a unique texture), Moiré patterns (screens produce interference patterns when photographed), depth cues (real faces have 3D depth that flat images lack), lighting consistency, and reflection patterns (real eyes have specular reflections that synthetic images lack).

C#
public class LivenessDetectionService
{
    private readonly IFaceModelClient _faceModelClient;
    private readonly IDepthEstimationService _depthService;

    public async Task<LivenessResult> DetectLivenessAsync(
        LivenessRequest request)
    {
        var result = new LivenessResult();

        // Phase 1: Passive liveness (texture + Moiré + depth)
        var passiveResult = await _faceModelClient
            .AnalyzePassiveLivenessAsync(request.SelfieImage);
        result.PassiveLivenessScore = passiveResult.Score;
        result.MoireDetected = passiveResult.MoirePatternPresent;
        result.DepthConsistent = passiveResult.DepthConsistent;

        // Phase 2: 3D depth estimation (single-image depth prediction)
        var depthMap = await _depthService
            .EstimateDepthAsync(request.SelfieImage);
        result.DepthVariance = CalculateDepthVariance(depthMap);
        result.Is3DConsistent = result.DepthVariance > 0.15;

        // Phase 3: Deepfake detection
        var deepfakeResult = await _faceModelClient
            .DetectDeepfakeAsync(request.SelfieImage);
        result.DeepfakeScore = deepfakeResult.Score;
        result.GanArtifactsDetected = deepfakeResult.GanArtifacts;

        // Phase 4: Temporal analysis (if video provided)
        if (request.SelfieVideo != null)
        {
            var temporalResult = await AnalyzeTemporalConsistency(
                request.SelfieVideo);
            result.BlinkDetected = temporalResult.BlinkCount > 0;
            result.HeadMovementDetected = temporalResult.HeadMovement;
            result.TemporalConsistency = temporalResult.Consistency;
        }

        // Combine scores with weighted average
        result.LivenessScore = result.PassiveLivenessScore * 0.35f +
            (result.Is3DConsistent ? 1.0f : 0.2f) * 0.25f +
            (1.0f - result.DeepfakeScore) * 0.25f +
            result.TemporalConsistency * 0.15f;

        result.IsLive = result.LivenessScore > 0.85f;
        return result;
    }
}

Active Liveness (Challenge-Response)

Active liveness requires the user to perform specific actions that are difficult to fake. Common challenges include: "Smile", "Turn head left/right", "Blink twice", and "Read the numbers shown". The challenge-response flow must be completed within 10 seconds and should use at least 3 randomly selected challenges to prevent pre-recorded replay attacks.

3D Depth Analysis

Newer smartphones with TrueDepth (iPhone) or structured light sensors can provide real 3D depth maps. When available, the platform uses this hardware depth data for the most reliable liveness detection. For devices without depth sensors, ML-based monocular depth estimation predicts 3D depth from a single 2D image.

Liveness MethodAccuracyUser ExperienceDevice Requirements
Passive (no interaction)97-99%Best (no extra steps)Standard camera
Active (challenge-response)99-99.5%Good (1-2 extra steps)Standard camera
3D Depth (hardware)99.5-99.9%Best (no extra steps)TrueDepth / LiDAR sensor
3D Depth (ML-estimated)96-98%Best (no extra steps)Standard camera
Deepfake Arms Race: Deepfake technology is advancing rapidly. In 2024, researchers demonstrated deepfake videos that fool state-of-the-art detection models with up to 40% success rates. The platform must continuously retrain its deepfake detection models on the latest attack vectors and update models at least quarterly. The defense-in-depth approach (passive + active + 3D) ensures that even if one layer is bypassed, the others catch the attack.

7. Face Matching — Selfie vs. ID Photo

Face matching compares the user's live selfie against the photograph on their identity document to confirm they are the same person. The face matching model must handle significant variations: different lighting, different angles, aging (ID photos may be years old), makeup changes, facial hair changes, and glasses differences. Modern face recognition models achieve 99.5%+ accuracy on benchmark datasets like LFW and MegaFace.

Face Matching Pipeline

graph LR A["ID Photo"] --> B["Face Detection"] C["Selfie"] --> B B --> D["Landmark Alignment"] D --> E["Feature Extraction (CNN)"] E --> F["Embedding Vector (512-d)"] F --> G["Cosine Similarity"] G --> H{"Similarity > Threshold?"} H -->|Yes| I["Match: Same Person"] H -->|No| J["No Match: Different Person"]
C#
public class FaceMatchingService
{
    private readonly IFaceDetectionModel _faceDetector;
    private readonly IFaceRecognitionModel _faceRecognizer;
    private const float MATCH_THRESHOLD = 0.65f;
    private const float HIGH_CONFIDENCE_THRESHOLD = 0.80f;

    public async Task<FaceMatchResult> MatchFacesAsync(
        byte[] idPhoto, byte[] selfie)
    {
        // Step 1: Detect faces in both images
        var idFace = await _faceDetector.DetectLargestFaceAsync(idPhoto);
        var selfieFace = await _faceDetector.DetectLargestFaceAsync(selfie);

        if (idFace == null || selfieFace == null)
            return new FaceMatchResult
            {
                IsMatch = false,
                Error = "No face detected in one or both images"
            };

        // Step 2: Extract feature embeddings
        var idEmbedding = await _faceRecognizer
            .ExtractEmbeddingAsync(idPhoto, idFace);
        var selfieEmbedding = await _faceRecognizer
            .ExtractEmbeddingAsync(selfie, selfieFace);

        // Step 3: Compute cosine similarity
        var similarity = CosineSimilarity(
            idEmbedding.Vector, selfieEmbedding.Vector);

        // Step 4: Compare against thresholds
        return new FaceMatchResult
        {
            SimilarityScore = similarity,
            IsMatch = similarity >= MATCH_THRESHOLD,
            IsHighConfidence = similarity >= HIGH_CONFIDENCE_THRESHOLD,
            Decision = similarity switch
            {
                >= HIGH_CONFIDENCE_THRESHOLD => MatchDecision.HighConfidenceMatch,
                >= MATCH_THRESHOLD => MatchDecision.Match,
                >= 0.50f => MatchDecision.LowConfidence,
                _ => MatchDecision.NoMatch
            }
        };
    }

    private static float CosineSimilarity(float[] a, float[] b)
    {
        float dotProduct = 0, normA = 0, normB = 0;
        for (int i = 0; i < a.Length; i++)
        {
            dotProduct += a[i] * b[i];
            normA += a[i] * a[i];
            normB += b[i] * b[i];
        }
        return dotProduct / (MathF.Sqrt(normA) * MathF.Sqrt(normB));
    }
}

Handling Edge Cases

Edge CaseChallengeMitigation
Aged ID photoPhoto taken 5+ years agoLower threshold for older documents, escalate to manual review
Heavy makeupSelfie has different appearanceML model trained on makeup variations, focus on bone structure
Glasses differenceGlasses in ID but not selfieExclude eye region from matching, focus on other features
Poor ID photo qualityBlurred or low-resolution ID photoReject low-quality captures, request re-capture
Twin/similar facesLow confidence distinguishingHigher threshold, escalate with additional checks
Threshold Calibration: The face matching threshold is configurable per deployment. A cryptocurrency exchange may set a higher threshold (0.75) to minimize fraud, while a gig economy platform may set a lower threshold (0.58) to minimize user friction. The platform monitors false acceptance and rejection rates continuously and can auto-adjust thresholds within client-defined bounds.

8. Document Fraud Detection (Tampering, Deepfakes)

Document fraud detection actively looks for signs that the document image has been tampered with. Fraudsters use Photoshop editing, printed documents, screen replays, and composite documents (combining elements from multiple genuine documents). The platform must detect each attack type with high accuracy.

Fraud Detection Techniques

Fraud TypeDetection MethodSignals
Photo substitutionEdge analysis, lighting consistency, JPEG compression analysisInconsistent JPEG quality, mismatched lighting, edge artifacts
Text editingFont consistency analysis, alignment checks, pixel-level forensicsFont mismatch, misalignment, inconsistent JPEG artifacts
Printed documentMoiré pattern detection, paper texture analysisPrinter dot patterns, paper texture, reduced color gamut
Screen captureScreen reflection detection, pixel grid analysisScreen glare, subpixel patterns, uneven brightness
Composite documentConsistency analysis across regionsMixed JPEG compression, inconsistent fonts, lighting mismatches

JPEG Forensics

JPEG compression leaves unique artifacts that reveal image manipulation. When a region is edited and re-saved, it acquires different compression artifacts than unedited regions. The JPEG forensics module analyzes the Double Quantization error pattern across the image to detect spliced regions. Error Level Analysis highlights regions with different compression levels, which often correspond to edited areas.

C#
public class DocumentFraudDetector
{
    private readonly IFraudDetectionModel _mlModel;
    private readonly IJpegForensics _jpegForensics;
    private readonly ISecurityFeatureAnalyzer _securityFeatures;

    public async Task<FraudDetectionResult> AnalyzeAsync(
        DocumentImage document)
    {
        var result = new FraudDetectionResult();

        // Layer 1: JPEG forensics
        var jpegAnalysis = await _jpegForensics.AnalyzeAsync(document);
        result.JpegConsistent = jpegAnalysis.IsConsistent;
        result.EditedRegions = jpegAnalysis.SuspiciousRegions;

        // Layer 2: ML-based fraud detection
        var mlResult = await _mlModel.DetectFraudAsync(document);
        result.FraudProbability = mlResult.Probability;
        result.FraudType = mlResult.PredictedFraudType;

        // Layer 3: Security feature verification
        var securityResult = await _securityFeatures.VerifyAsync(document);
        result.HologramPresent = securityResult.HologramDetected;
        result.UVFeaturesPresent = securityResult.UVDetected;
        result.SecurityFeatureScore = securityResult.OverallScore;

        // Layer 4: Consistency analysis
        result.ConsistencyScore = await AnalyzeConsistency(document);

        // Composite fraud score
        result.OverallFraudScore = CalculateFraudScore(
            result.JpegConsistent,
            result.FraudProbability,
            result.SecurityFeatureScore,
            result.ConsistencyScore);

        result.IsFraudulent = result.OverallFraudScore > 0.7f;
        result.RequiresManualReview =
            result.OverallFraudScore > 0.4f &&
            result.OverallFraudScore <= 0.7f;

        return result;
    }
}
AI-Generated Documents: In 2025, researchers demonstrated realistic fake identity documents generated using diffusion models. These AI-generated documents can bypass traditional template matching. The defense is forensics-level analysis — examining the image at the pixel level for GAN/diffusion artifacts, statistical anomalies in noise patterns, and inconsistencies in security features that AI models cannot reliably reproduce.

9. Watchlist Screening (PEP, Sanctions)

Watchlist screening checks whether the individual appears on government sanctions lists, is a Politically Exposed Person (PEP), or has adverse media coverage linking them to financial crime, terrorism, or other illicit activity. This is a legal requirement under AML regulations — financial institutions must not onboard sanctioned individuals and must apply enhanced due diligence to PEPs.

Watchlist Data Sources

SourceCoverageUpdate FrequencyType
OFAC SDN List (US)Global, 12,000+ entriesMultiple times per weekSanctions
UN Security CouncilGlobal, 1,500+ entriesAs decisions are madeSanctions
EU Consolidated ListEuropean, 10,000+ entriesWeeklySanctions
UK HMT SanctionsUK-specific, 5,000+ entriesWeeklySanctions
PEP DatabaseGlobal, 500,000+ PEPsDailyPolitically Exposed Persons
Adverse MediaGlobal news sourcesDailyReputation risk

Fuzzy Name Matching

Name matching across watchlists is deceptively complex. Names are transliterated differently (Muhammad/Mohammed/Mohamed), have spelling variations (O'Brien/Obrien), may be in different scripts (Cyrillic, Arabic, Chinese), and may include titles or suffixes. The matching engine uses: exact matching, phonetic matching (Soundex, Metaphone), fuzzy string matching (Levenshtein distance, Jaro-Winkler similarity), transliteration matching, and ML-based matching.

C#
public class WatchlistScreeningService
{
    private readonly IWatchlistDatabase _watchlistDb;
    private readonly INameMatchingEngine _nameMatcher;
    private readonly IPhoneticEncoder _phoneticEncoder;

    public async Task<WatchlistResult> ScreenAsync(
        ScreeningRequest request)
    {
        var result = new WatchlistResult();
        var normalizedName = NormalizeName(request.FullName);

        // Pass 1: Exact match (fast path)
        var exactMatches = await _watchlistDb
            .FindExactMatchesAsync(normalizedName);
        if (exactMatches.Any())
        {
            result.ExactMatches = exactMatches;
            result.RequiresManualReview = true;
        }

        // Pass 2: Fuzzy + phonetic matching
        var candidates = await _watchlistDb
            .GetCandidatesByCountryAsync(request.CountryCode);

        foreach (var candidate in candidates)
        {
            var nameScore = _nameMatcher.CalculateSimilarity(
                normalizedName, candidate.NormalizedName);

            var phoneticMatch = _phoneticEncoder.Encode(normalizedName) ==
                _phoneticEncoder.Encode(candidate.NormalizedName);

            if (nameScore > 0.75f || phoneticMatch)
            {
                var match = new WatchlistMatch
                {
                    WatchlistEntry = candidate,
                    NameSimilarityScore = nameScore,
                    PhoneticMatch = phoneticMatch,
                    DOBMatch = request.DateOfBirth == candidate.DateOfBirth,
                    OverallScore = CalculateMatchScore(
                        nameScore, phoneticMatch,
                        request.DateOfBirth == candidate.DateOfBirth,
                        request.Nationality == candidate.Nationality)
                };

                if (match.OverallScore > 0.6f)
                    result.PotentialMatches.Add(match);
            }
        }

        result.IsSanctioned = result.ExactMatches
            .Any(m => m.ListType == WatchlistType.Sanctions);
        result.IsPEP = result.PotentialMatches
            .Any(m => m.WatchlistEntry.Type == WatchlistType.PEP &&
                        m.OverallScore > 0.8f);
        result.HasAdverseMedia = await CheckAdverseMediaAsync(
            request.FullName);

        result.ScreeningDecision = DetermineDecision(result);
        return result;
    }
}
Sanctions Compliance: Onboarding a sanctioned individual is a criminal offense in most jurisdictions, with penalties including imprisonment and fines exceeding $1 billion. The watchlist screening must be thorough and auditable — every screening decision must be logged with the full evidence trail (which lists were checked, which matches were found, what scores were computed, and who made the final decision).

10. AML Risk Scoring

AML risk scoring assigns a composite risk score to each verification attempt, combining signals from all verification checks to determine the overall risk level of onboarding this individual. The risk score drives the verification decision: low-risk individuals are auto-approved, medium-risk are escalated to manual review, and high-risk are rejected or subject to enhanced due diligence. The model must be transparent and auditable — regulators require the ability to understand why a particular individual was classified as high or low risk.

Risk Scoring Model

graph TB A["Verification Inputs"] --> B["Document Risk"] A --> C["Biometric Risk"] A --> D["Watchlist Risk"] A --> E["Country Risk"] A --> F["Address Risk"] A --> G["Device Risk"] B --> H["Weighted Risk Model"] C --> H D --> H E --> H F --> H G --> H H --> I["Composite Risk Score (0-100)"] I --> J{"Score Range"} J -->|0-30| K["LOW: Auto-Approve"] J -->|31-70| L["MEDIUM: Manual Review"] J -->|71-100| M["HIGH: Reject / EDD"]
C#
public class AmlRiskScoringService
{
    private readonly RiskWeights _weights;

    public RiskScore CalculateRiskScore(VerificationSignals signals)
    {
        var scores = new Dictionary<string, float>
        {
            ["document"] = 1.0f - signals.DocumentAuthenticityScore,
            ["biometric"] = 1.0f - signals.FaceMatchScore,
            ["watchlist"] = signals.WatchlistRiskScore,
            ["country"] = GetCountryRiskScore(signals.Nationality),
            ["address"] = GetAddressRiskScore(signals.Address),
            ["document_age"] = GetDocumentAgeRisk(
                signals.DocumentExpiryDate),
            ["device"] = signals.DeviceRiskScore,
            ["behavioral"] = signals.BehavioralRiskScore
        };

        float compositeScore = 0;
        foreach (var (factor, score) in scores)
            compositeScore += score * _weights.GetWeight(factor);

        compositeScore = Math.Clamp(compositeScore, 0f, 100f);

        return new RiskScore
        {
            CompositeScore = compositeScore,
            FactorScores = scores,
            RiskLevel = compositeScore switch
            {
                <= 30 => RiskLevel.Low,
                <= 70 => RiskLevel.Medium,
                _ => RiskLevel.High
            },
            RecommendedAction = compositeScore switch
            {
                <= 30 => Action.AutoApprove,
                <= 70 => Action.ManualReview,
                _ => Action.RejectOrEDD
            }
        };
    }

    private float GetCountryRiskScore(string nationality)
    {
        var highRisk = new HashSet<string> { "KP", "IR", "MM" };
        var greyList = new HashSet<string>
            { "PK", "LB", "UG", "TZ", "MU" };

        if (highRisk.Contains(nationality)) return 0.9f;
        if (greyList.Contains(nationality)) return 0.6f;
        return 0.2f;
    }
}

Risk Factor Weights

FactorWeightRationale
Document authenticity25%Forged documents are the strongest indicator of fraud
Biometric match20%Non-match indicates the person is not the document holder
Watchlist match20%Sanctions matches are legally required blockers
Country risk15%FATF grey/black list countries have higher AML risk
Address risk10%High-risk jurisdictions increase risk
Device/behavioral10%Anomalous behavior indicates potential fraud

11. Address Verification

Address verification confirms that the address provided matches a real, verifiable address and, where required, matches the address on the identity document. The platform supports three verification methods: database verification (checking against utility company or government databases), document-based verification (extracting the address from the ID document), and third-party verification (using services like USPS address validation or Google Maps Geocoding API).

Address Verification Methods

MethodCoverageAccuracyLatency
Utility database check60% of addresses (US, UK, EU)99%1-3 seconds
Government database check30% (varies by country)99.5%2-10 seconds
USPS/courier validationUS addresses only99.9%< 1 second
Document-based extractionAll countries (if on ID)OCR-dependent (95%+)< 1 second
Geocoding validationGlobal85%< 1 second

The address verification flow first normalizes the address using the Address Data Council standards, then attempts database verification where available. If no database is available, the system falls back to geocoding and document-based extraction. The verification result includes a confidence score and the verification method used, which the risk scoring model factors into its calculation.

12. Phone & Email Verification

Phone and email verification serve dual purposes: confirming the user's contact channels are legitimate (not disposable or fraudulent), and providing a channel for ongoing communication. Phone verification uses SMS or voice OTP. Email verification uses a confirmation link or OTP. Both channels are checked against risk databases — disposable email providers, VoIP phone numbers, and known fraud-associated numbers are flagged.

Phone Verification Flow

C#
public class PhoneVerificationService
{
    private readonly ISmsProvider _smsProvider;
    private readonly IPhoneIntelligence _phoneIntelligence;
    private readonly IVerificationStore _store;

    public async Task<PhoneVerificationResult> VerifyAsync(
        string phoneNumber, string countryCode)
    {
        var result = new PhoneVerificationResult();

        if (!PhoneNumberValidator.IsValid(phoneNumber, countryCode))
        {
            result.Status = PhoneVerificationStatus.Invalid;
            return result;
        }

        var intel = await _phoneIntelligence.AnalyzeAsync(phoneNumber);
        result.IsDisposable = intel.IsDisposable;
        result.IsVoip = intel.IsVoip;

        if (intel.IsDisposable)
        {
            result.Status = PhoneVerificationStatus.Rejected;
            result.Reason = "Disposable phone number not accepted";
            return result;
        }

        var otp = GenerateSecureOtp(6);
        var otpExpiry = DateTime.UtcNow.AddMinutes(5);
        await _store.StoreOtpAsync(phoneNumber, otp, otpExpiry);
        await _smsProvider.SendAsync(phoneNumber,
            $"Your verification code is: {otp}. Valid for 5 minutes.");

        result.Status = PhoneVerificationStatus.OtpSent;
        result.AttemptsRemaining = 3;
        return result;
    }

    public async Task<PhoneVerificationResult> ConfirmOtpAsync(
        string phoneNumber, string code)
    {
        var stored = await _store.GetOtpAsync(phoneNumber);

        if (stored == null || stored.Expiry < DateTime.UtcNow)
            return new PhoneVerificationResult
                { Status = PhoneVerificationStatus.Expired };

        if (stored.Attempts >= 3)
            return new PhoneVerificationResult
                { Status = PhoneVerificationStatus.Locked };

        if (stored.Code != code)
        {
            stored.Attempts++;
            await _store.UpdateOtpAsync(stored);
            return new PhoneVerificationResult
            {
                Status = PhoneVerificationStatus.Incorrect,
                AttemptsRemaining = 3 - stored.Attempts
            };
        }

        await _store.MarkVerifiedAsync(phoneNumber);
        return new PhoneVerificationResult
        {
            Status = PhoneVerificationStatus.Verified,
            VerifiedAt = DateTime.UtcNow
        };
    }
}

Email Risk Checks

Before sending a verification email, the system performs risk checks: domain age (newly registered domains are suspicious), disposable email detection (checking against 10,000+ known providers), free email provider detection (Gmail, Yahoo flagged for higher-risk verifications), role-based email detection (admin@, info@ flagged), and SMTP RCPT TO verification (confirming the address accepts mail without sending actual mail).

13. Database Verification (Government Databases)

Database verification cross-references the extracted document data against authoritative government or institutional databases to confirm the document is genuine and hasn't been reported lost, stolen, or cancelled. The platform supports three verification tiers: full verification (real-time API check), limited verification (batch check with 24-hour turnaround), and document-only (no database available).

Database Verification by Country

CountryAvailable DatabasesVerification TypeLatency
United StatesSSA, DMV, USPSReal-time API1-3 seconds
United KingdomDVLA, Royal MailReal-time API1-5 seconds
GermanyMeldebescheinigungLimited (batch)24 hours
IndiaAadhaar (UIDAI)Real-time API (with consent)2-5 seconds
BrazilRG, CPFLimited (batch)1-3 days
NigeriaNIMC (NIN)Limited (batch)1-5 days
JapanMy Number CardReal-time API1-3 seconds
AustraliaDocument Verification ServiceReal-time API1-2 seconds

When a database check returns a positive match, the verification confidence increases significantly — the combination of document analysis + biometric matching + database verification produces a near-certain verification. When no database is available, the platform relies on other verification signals and may apply additional checks to compensate.

Database Partnership Strategy: Establishing database partnerships is often the most time-consuming part of building a global KYC platform. Each government agency has its own API specifications, data formats, authentication mechanisms, and commercial terms. The platform should maintain a "database availability matrix" that tracks which databases are available in which countries, updated quarterly.

14. KYC Workflow — Collection to Approval

The KYC workflow is the state machine that governs the entire verification process from initial document submission to final approval or rejection. It must handle the full lifecycle: collecting documents, running automated checks, routing to manual review when needed, handling re-submissions, and maintaining an audit trail of every state transition.

stateDiagram-v2 [*] --> DocumentCollection DocumentCollection --> DocumentAnalysis: Document uploaded DocumentAnalysis --> SelfieCollection: Document verified SelfieCollection --> BiometricVerification: Selfie captured BiometricVerification --> WatchlistScreening: Face matched WatchlistScreening --> AmlRiskScoring: Watchlist cleared AmlRiskScoring --> AutoApprove: Risk score low AmlRiskScoring --> ManualReview: Risk score medium AmlRiskScoring --> AutoReject: Risk score high ManualReview --> Approved: Analyst approved ManualReview --> Rejected: Analyst rejected ManualReview --> ResubmitRequest: Need more info ResubmitRequest --> DocumentCollection: Documents resubmitted AutoApprove --> [*] AutoReject --> [*] Approved --> [*] Rejected --> [*]
C#
public class KycWorkflowEngine
{
    private readonly IVerificationStore _store;
    private readonly IVerificationOrchestrator _orchestrator;
    private readonly IWebhookDispatcher _webhooks;

    public async Task<KycResult> ProcessVerificationAsync(
        KycVerificationRequest request)
    {
        var verification = new Verification
        {
            Id = Guid.NewGuid(),
            ClientId = request.ClientId,
            UserId = request.UserId,
            Status = VerificationStatus.DocumentCollection,
            CreatedAt = DateTime.UtcNow
        };

        await _store.SaveAsync(verification);

        // Step 1: Document Analysis
        verification.Status = VerificationStatus.DocumentAnalysis;
        var docResult = await _orchestrator
            .AnalyzeDocumentAsync(request.DocumentImages);
        verification.DocumentResult = docResult;
        await UpdateAndNotify(verification);

        // Step 2: Selfie & Biometric Verification
        verification.Status = VerificationStatus.BiometricVerification;
        var biometricResult = await _orchestrator
            .VerifyBiometricAsync(request.SelfieImage,
                docResult.ExtractedPhoto);
        verification.BiometricResult = biometricResult;
        await UpdateAndNotify(verification);

        // Step 3: Watchlist Screening
        verification.Status = VerificationStatus.WatchlistScreening;
        var watchlistResult = await _orchestrator
            .ScreenWatchlistAsync(docResult.ExtractedData);
        verification.WatchlistResult = watchlistResult;
        await UpdateAndNotify(verification);

        // Step 4: AML Risk Scoring
        verification.Status = VerificationStatus.RiskScoring;
        var riskScore = await _orchestrator
            .CalculateRiskScoreAsync(verification);
        verification.RiskScore = riskScore;
        await UpdateAndNotify(verification);

        // Step 5: Decision
        verification.Status = riskScore.RiskLevel switch
        {
            RiskLevel.Low => VerificationStatus.Approved,
            RiskLevel.High => VerificationStatus.Rejected,
            RiskLevel.Medium => VerificationStatus.ManualReview
        };

        verification.CompletedAt = DateTime.UtcNow;
        await _store.SaveAsync(verification);

        await _webhooks.SendAsync(request.CallbackUrl, new WebhookPayload
        {
            VerificationId = verification.Id,
            Status = verification.Status,
            RiskScore = riskScore.CompositeScore,
            Timestamp = verification.CompletedAt
        });

        return MapToResult(verification);
    }
}

Workflow States & Transitions

StateDescriptionNext StatesTrigger
DocumentCollectionWaiting for user to upload documentsDocumentAnalysisDocument uploaded
DocumentAnalysisOCR + authenticity checks runningSelfieCollectionAnalysis complete
SelfieCollectionWaiting for user to capture selfieBiometricVerificationSelfie captured
BiometricVerificationFace matching + liveness runningWatchlistScreeningBiometric check complete
WatchlistScreeningChecking sanctions/PEP databasesAmlRiskScoringScreening complete
AmlRiskScoringCalculating composite risk scoreApproved/Rejected/ManualReviewRisk score determined
ManualReviewAnalyst reviewing evidenceApproved/Rejected/ResubmitRequestAnalyst decision
ApprovedVerification passedTerminal
RejectedVerification failedTerminal
Idempotent Workflow Steps: Each workflow step is idempotent — re-running the same step with the same inputs produces the same outputs. This is critical for reliability: if the workflow crashes mid-step and restarts, it can safely re-run the last step without corrupting the verification state. The workflow engine uses a "check-then-act" pattern: before running a step, it checks if the step already completed successfully.

15. Tiered Verification Levels

Not all use cases require the same level of verification. The platform supports configurable verification tiers that clients can select based on their regulatory requirements and risk appetite.

Verification Tiers

TierChecks IncludedTypical Use CaseCompletion Time
Tier 1 — BasicDocument verification + selfie matchFreelance marketplaces, social media age verification15-20 seconds
Tier 2 — StandardTier 1 + liveness + watchlist screeningFintech, neobanks, insurance20-30 seconds
Tier 3 — EnhancedTier 2 + AML risk scoring + address verificationCryptocurrency exchanges, trading platforms25-35 seconds
Tier 4 — FullTier 3 + database + phone/email verificationBanks, lending, regulated financial services30-60 seconds
C#
public class VerificationTierConfigurator
{
    public VerificationPipeline GetPipeline(VerificationTier tier)
    {
        return tier switch
        {
            VerificationTier.Basic => new VerificationPipeline
            {
                Steps = new[]
                {
                    VerificationStep.DocumentAnalysis,
                    VerificationStep.FaceMatching
                },
                AutoApproveThreshold = 0.70f,
                AutoRejectThreshold = 0.30f
            },
            VerificationTier.Standard => new VerificationPipeline
            {
                Steps = new[]
                {
                    VerificationStep.DocumentAnalysis,
                    VerificationStep.FaceMatching,
                    VerificationStep.LivenessDetection,
                    VerificationStep.WatchlistScreening
                },
                AutoApproveThreshold = 0.75f,
                AutoRejectThreshold = 0.25f
            },
            VerificationTier.Enhanced => new VerificationPipeline
            {
                Steps = new[]
                {
                    VerificationStep.DocumentAnalysis,
                    VerificationStep.FaceMatching,
                    VerificationStep.LivenessDetection,
                    VerificationStep.WatchlistScreening,
                    VerificationStep.AmlRiskScoring,
                    VerificationStep.AddressVerification
                },
                AutoApproveThreshold = 0.80f,
                AutoRejectThreshold = 0.20f
            },
            VerificationTier.Full => new VerificationPipeline
            {
                Steps = new[]
                {
                    VerificationStep.DocumentAnalysis,
                    VerificationStep.FaceMatching,
                    VerificationStep.LivenessDetection,
                    VerificationStep.WatchlistScreening,
                    VerificationStep.AmlRiskScoring,
                    VerificationStep.AddressVerification,
                    VerificationStep.PhoneVerification,
                    VerificationStep.EmailVerification,
                    VerificationStep.DatabaseVerification
                },
                AutoApproveThreshold = 0.85f,
                AutoRejectThreshold = 0.15f
            }
        };
    }
}

Clients can create custom tiers by selecting specific verification steps and configuring their own thresholds. The platform provides a configuration API that allows real-time tier setting updates with versioning and rollback capability.

16. Re-verification & Ongoing Monitoring

KYC is not a one-time event — it is an ongoing process. Customers must be re-verified periodically (typically annually for standard risk, quarterly for high risk), when their risk profile changes, or when their identity documents expire.

Re-verification Triggers

TriggerFrequencyActionCustomer Impact
Document expiryWhen expiry date reachedRequest new documentAccount restricted until provided
Periodic re-verification12 months (low), 6 months (medium), 3 months (high)Full re-verification flow30-day grace period
New watchlist matchReal-time (daily batch)Immediate enhanced reviewAccount may be frozen
Adverse media matchDaily scanEnhanced due diligenceAccount may be restricted
Risk score changeContinuousRe-evaluate risk tierMay trigger additional checks
C#
public class ReverificationScheduler
{
    private readonly IVerificationStore _store;

    public async Task CheckReverificationTriggersAsync()
    {
        var expiredDocs = await _store
            .GetVerificationsWithExpiredDocumentsAsync();
        foreach (var v in expiredDocs)
            await TriggerReverificationAsync(v,
                ReverificationTrigger.DocumentExpiry);

        var dueForPeriodic = await _store
            .GetVerificationsDueForPeriodicReviewAsync();
        foreach (var v in dueForPeriodic)
        {
            var interval = GetReverificationInterval(v.RiskLevel);
            if (DateTime.UtcNow - v.LastVerifiedAt >= interval)
                await TriggerReverificationAsync(v,
                    ReverificationTrigger.Periodic);
        }
    }

    private TimeSpan GetReverificationInterval(RiskLevel level)
    {
        return level switch
        {
            RiskLevel.Low => TimeSpan.FromDays(365),
            RiskLevel.Medium => TimeSpan.FromDays(180),
            RiskLevel.High => TimeSpan.FromDays(90),
            _ => TimeSpan.FromDays(365)
        };
    }
}
Customer Communication: Re-verification requests must be communicated clearly with sufficient lead time. The platform sends automated notifications 30 days before re-verification is due, with weekly reminders. Customers who do not complete re-verification within the grace period have their accounts progressively restricted — first limiting new transactions, then withdrawals, then full account freeze.

17. Embedded Verification SDK & Webhook Callbacks

The verification SDK is the primary integration point for clients. It provides embeddable JavaScript components for web and native SDKs for iOS and Android. The SDK handles the entire capture flow with real-time quality guidance, uploads images directly to encrypted storage, and manages the verification lifecycle.

SDK Integration Example

C#
// Server-side: Create a verification session and get a client token
[HttpPost("api/verification/start")]
public async Task<ActionResult> StartVerification(
    [FromBody] VerificationRequest request)
{
    var session = await _kycService.CreateSessionAsync(
        new SessionRequest
        {
            ClientId = _authContext.ClientId,
            UserId = request.UserId,
            Tier = VerificationTier.Standard,
            CallbackUrl = request.CallbackUrl,
            Metadata = request.Metadata
        });

    return Ok(new
    {
        SessionId = session.Id,
        ClientToken = session.ClientToken,
        Expiry = session.Expiry
    });
}

// Client-side: Initialize SDK (JavaScript)
const verification = await KYC.initialize({
    clientToken: "eyJhbGciOi...",
    container: "#kyc-container",
    steps: ["document", "selfie"],
    document: {
        types: ["passport", "driver_license", "national_id"],
        country: "US"
    },
    selfie: {
        liveness: "active",
        challenges: ["smile", "blink"]
    },
    onComplete: (result) => {
        console.log("Verification:", result.verificationId);
        console.log("Status:", result.status);
    },
    onError: (error) => {
        console.error("KYC Error:", error.code, error.message);
    }
});
verification.start();

Webhook Callbacks

Webhook callbacks notify clients when verification status changes. The platform sends HTTP POST requests with HMAC-SHA256 signed JSON payloads. Webhooks are retried with exponential backoff (3 retries over 30 minutes). Clients can register multiple callback URLs for redundancy.

JSON
{
    "event": "verification.completed",
    "verification_id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "approved",
    "risk_score": 15.2,
    "timestamp": "2025-07-15T14:30:00Z",
    "data": {
        "document_type": "passport",
        "document_country": "US",
        "face_match_score": 0.92,
        "liveness_score": 0.95,
        "watchlist_clear": true,
        "aml_risk_level": "low"
    },
    "signature": "a1b2c3d4e5f6..."
}
Webhook EventTriggerUse Case
verification.startedUser begins verification flowTrack funnel conversion
verification.completedAutomated decision madeGrant/deny access
verification.pending_reviewEscalated to manual reviewNotify operations team
verification.approvedFinal approvalGrant access
verification.rejectedFinal rejectionNotify user, deny access
verification.resubmission_requiredAnalyst requests new documentsPrompt user to re-upload
Webhook Reliability: The webhook delivery system guarantees at-least-once delivery with idempotent event processing. Each event has a unique event_id for deduplication. The system maintains a webhook event log that clients can query via API to recover missed events.

18. Multi-Country Support & Data Residency

A global KYC platform must support identity documents from 190+ countries while complying with data residency regulations that require certain data to be stored within specific geographic boundaries.

Data Residency Requirements by Region

RegionRegulationRequirementImplementation
European UnionGDPRPersonal data must stay in EUEU-hosted storage cluster
BrazilLGPDProcessing consent requiredBrazilian data center
IndiaDPDP ActCritical data must be stored in IndiaIndian data center for Aadhaar
ChinaPIPLCross-border transfer requires assessmentChina-hosted processing
RussiaFederal Law 152Russian citizen data in RussiaRussian data center
United StatesCCPA/CPRARight to deletion, opt-outUS-hosted storage, deletion API
graph TB subgraph Global["Global Platform"] API["Global API Gateway"] Orch["Verification Orchestrator"] end subgraph EU["EU Region"] EU_DB["EU PostgreSQL"] EU_S3["EU S3 Bucket"] EU_ML["EU ML Services"] end subgraph US["US Region"] US_DB["US PostgreSQL"] US_S3["US S3 Bucket"] US_ML["US ML Services"] end subgraph APAC["APAC Region"] APAC_DB["APAC PostgreSQL"] APAC_S3["APAC S3 Bucket"] APAC_ML["APAC ML Services"] end API --> Orch Orch -->|EU user| EU_DB Orch -->|US user| US_DB Orch -->|APAC user| APAC_DB EU_DB --> EU_S3 US_DB --> US_S3 APAC_DB --> APAC_S3

The routing layer examines the user's declared nationality, IP geolocation, and client configuration to determine the appropriate data region. Document images and PII are processed and stored within the determined region. ML models are deployed to each region to avoid cross-border data transfer during inference.

19. API Design

The platform exposes a RESTful API for verification management, status queries, and administrative operations. All API calls are authenticated via API keys (server-to-server) or client tokens (browser/mobile SDK).

Verification API

HTTP
POST   /api/v1/verifications                    # Create verification session
GET    /api/v1/verifications/{id}               # Get verification details
GET    /api/v1/verifications/{id}/status        # Get current status (lightweight)
GET    /api/v1/verifications/{id}/documents     # Get extracted document data
GET    /api/v1/verifications/{id}/decision      # Get decision details
POST   /api/v1/verifications/{id}/resubmit      # Request document resubmission
POST   /api/v1/verifications/{id}/approve       # Manual approval (reviewer)
POST   /api/v1/verifications/{id}/reject        # Manual rejection (reviewer)
GET    /api/v1/verifications?status=pending_review  # List verifications (filtered)
POST   /api/v1/screening                        # Run watchlist screening
GET    /api/v1/screening/{id}                    # Get screening results
GET    /api/v1/config/tiers                      # Get verification tier configs
PUT    /api/v1/config/tiers/{tier}               # Update tier configuration
GET    /api/v1/audit/verifications/{id}          # Get full audit trail

Create Verification Request

JSON
{
    "user_id": "user_abc123",
    "type": "kyc",
    "tier": "standard",
    "documents": [
        {
            "type": "passport",
            "country": "US",
            "images": {
                "front": "https://upload.example.com/doc_front.jpg?token=...",
                "back": null
            }
        }
    ],
    "selfie": {
        "type": "live_capture",
        "liveness": "active"
    },
    "callback_url": "https://api.mysite.com/webhooks/kyc",
    "redirect_url": "https://mysite.com/kyc/complete",
    "metadata": {
        "account_id": "acc_12345",
        "flow": "onboarding"
    },
    "options": {
        "manual_review": true,
        "data_deletion_after_days": 365
    }
}

API Error Handling

Status CodeError TypeDescription
400invalid_requestMissing required fields or invalid format
401unauthorizedInvalid or missing API key
403forbiddenAPI key lacks permission
404not_foundVerification doesn't exist
409conflictVerification already exists for this user
429rate_limitedToo many requests, retry after Retry-After
500internal_errorServer error, contact support
API Idempotency: All POST requests accept an optional Idempotency-Key header. If provided, the server returns the same response for duplicate requests within a 24-hour window. This prevents duplicate verifications from network retries.

20. Security & Biometric Data Protection

Biometric data (face images, facial embeddings, fingerprints) is among the most sensitive categories of personal data. Unlike a password, biometric data cannot be changed if compromised. The platform implements defense-in-depth security across every layer.

Security Architecture

LayerProtectionImplementation
Data at restAES-256 encryptionAWS KMS / Azure Key Vault, encrypted S3 and RDS
Data in transitTLS 1.3Certificate pinning in SDKs, HSTS, min TLS enforcement
Access controlRBAC + MFAAnalyst roles (reviewer, admin, auditor), MFA required
Audit loggingImmutable audit trailS3 Object Lock, append-only log store, 7-year retention
Data minimizationDelete when unnecessaryConfigurable retention policies, auto PII deletion
PseudonymizationToken-based referencesInternal systems use verification tokens, not raw PII
Network securityVPC isolationPrivate subnets for ML services, WAF, DDoS protection
Secret managementCentralized vaultHashiCorp Vault / AWS Secrets Manager, dynamic secrets
C#
public class BiometricDataProtector
{
    private readonly IKeyVault _keyVault;
    private readonly IEncryptionService _encryption;

    public async Task<EncryptedBiometricData> EncryptBiometricAsync(
        BiometricData data, Guid userId)
    {
        // Generate a unique data encryption key (DEK) for this user
        var dek = await _keyVault.GenerateDataKeyAsync(
            keySize: 256,
            context: $"biometric:{userId}");

        // Encrypt the facial embedding
        var encryptedEmbedding = _encryption.EncryptAes256(
            data.FacialEmbedding, dek.Plaintext);

        // Encrypt the selfie image
        var encryptedSelfie = _encryption.EncryptAes256(
            data.SelfieImage, dek.Plaintext);

        // Encrypt the DEK with the master key (envelope encryption)
        var encryptedDek = _encryption.EncryptRsa(
            dek.Plaintext,
            await _keyVault.GetMasterKeyAsync("biometric"));

        // Securely erase the plaintext DEK from memory
        dek.ZeroPlaintext();

        return new EncryptedBiometricData
        {
            UserId = userId,
            EncryptedEmbedding = encryptedEmbedding,
            EncryptedSelfie = encryptedSelfie,
            EncryptedDek = encryptedDek,
            Algorithm = "AES-256-GCM",
            KeyVersion = await _keyVault.GetCurrentKeyVersionAsync(),
            CreatedAt = DateTime.UtcNow
        };
    }
}

Biometric Data Lifecycle

graph LR A["Capture (Client)"] --> B["Upload (TLS 1.3)"] B --> C["Encrypt (AES-256)"] C --> D["Process (ML Inference)"] D --> E["Store (Encrypted S3)"] E --> F{"Retention Period"} F -->|Active| G["Available for Re-verification"] F -->|Expired| H["Secure Deletion"] H --> I["Audit Log Entry"]
Breach Response: A biometric data breach requires immediate action. The platform must detect breaches within 1 hour (via anomaly detection on access patterns), notify affected users and regulators within 72 hours (GDPR requirement), revoke all encryption keys for the compromised data, and provide affected users with mitigation guidance. The incident response plan is tested quarterly via tabletop exercises.

21. Compliance (KYC/AML, GDPR, CCPA)

Compliance is the foundation of the platform. Every design decision must consider regulatory requirements. The three primary frameworks are KYC/AML regulations (financial crime prevention), GDPR (European data protection), and CCPA/CPRA (California consumer privacy).

Regulatory Requirements Matrix

RequirementKYC/AMLGDPRCCPA/CPRA
Data collectionMandatory for financial servicesMust have lawful basisMust disclose categories
Data processingRequired for complianceMust be necessary and proportionateMust disclose purposes
Data retentionMinimum 5 yearsNo longer than necessaryRetain only as disclosed
Data deletionCannot delete if under investigationRight to erasure (72-hour SLA)Right to delete (45-day SLA)
Data portabilityNot requiredRight to data portabilityRight to data portability
Cross-border transferVaries by jurisdictionRequires adequacy decision or SCCsNot specifically restricted
Breach notificationReport to FIU within 24 hoursAuthority: 72 hoursConsumers: most expedient time
C#
public class GdprComplianceService
{
    private readonly IVerificationStore _store;
    private readonly IBiometricStore _biometricStore;
    private readonly IAuditLogger _auditLogger;

    public async Task<ErasureResult> ProcessErasureRequestAsync(
        ErasureRequest request)
    {
        var activeInvestigations = await _store
            .GetActiveInvestigationsAsync(request.UserId);

        if (activeInvestigations.Any())
        {
            await _auditLogger.LogAsync(new AuditEntry
            {
                Action = "erasure_denied",
                UserId = request.UserId,
                Reason = "Active AML investigation",
                LegalBasis = "GDPR Art. 17(3)(b)",
                Timestamp = DateTime.UtcNow
            });

            return new ErasureResult
            {
                Status = ErasureStatus.Denied,
                Reason = "Legal obligation requires data retention"
            };
        }

        // Delete biometric data
        await _biometricStore.DeleteAllBiometricsAsync(request.UserId);

        var verifications = await _store
            .GetVerificationsAsync(request.UserId);
        foreach (var v in verifications)
        {
            if (v.RetentionRequired)
                await _store.AnonymizeAsync(v.Id);
            else
                await _store.DeleteAsync(v.Id);
        }

        await _auditLogger.LogAsync(new AuditEntry
        {
            Action = "erasure_completed",
            UserId = request.UserId,
            RecordsAnonymized = verifications.Count(v => v.RetentionRequired),
            RecordsDeleted = verifications.Count(v => !v.RetentionRequired),
            Timestamp = DateTime.UtcNow
        });

        return new ErasureResult { Status = ErasureStatus.Completed };
    }
}
Conflicting Regulations: GDPR's right to erasure can conflict with AML's record retention requirements. The platform resolves this by applying a hierarchy: AML record retention takes precedence over GDPR erasure when there is an active investigation or the retention period has not expired. The platform documents the legal basis for each retention decision (GDPR Article 17(3)(b)) and provides this documentation to regulators upon request.

22. Monitoring & Alerting

Monitoring for a KYC platform must track both system health metrics (latency, error rates, throughput) and business metrics (approval rates, false rejection rates, fraud detection rates). A system that is technically healthy but rejecting 20% of legitimate users is just as broken as one returning HTTP 500 errors.

Key Metrics Dashboard

MetricAlert ThresholdSeverity
Verification latency P99> 45 secondsWarning
Automated approval rate< 80%Warning
False rejection rate> 3%Critical
Manual review queue depth> 1,000Warning
Manual review SLA breach> 5% exceed 4 hoursCritical
ML model accuracy< 97% on benchmarkCritical
Fraud detection rate< 95%Critical
OCR accuracy< 95% character-levelWarning
API error rate> 1%Critical
SDK crash rate> 0.5%Warning

ML Model Monitoring

ML model performance degrades over time as fraudsters evolve their techniques. The platform continuously monitors model performance against known-good and known-fraud datasets, retrains models when performance drops below thresholds, and A/B tests new versions before full deployment.

C#
public class ModelPerformanceMonitor
{
    private readonly IMetricsCollector _metrics;
    private readonly IAlertService _alerts;

    public async Task EvaluateModelPerformanceAsync(
        string modelName, ModelPerformanceData data)
    {
        var accuracy = (float)(data.TruePositives + data.TrueNegatives) /
            data.TotalPredictions;
        var precision = (float)data.TruePositives /
            (data.TruePositives + data.FalsePositives);
        var recall = (float)data.TruePositives /
            (data.TruePositives + data.FalseNegatives);
        var f1 = 2 * (precision * recall) / (precision + recall);

        _metrics.Gauge("ml.model.accuracy", accuracy,
            new Tags { ["model"] = modelName });
        _metrics.Gauge("ml.model.f1", f1,
            new Tags { ["model"] = modelName });

        if (accuracy < 0.97f)
        {
            await _alerts.SendAsync(new Alert
            {
                Severity = AlertSeverity.Critical,
                Title = $"ML model accuracy below threshold",
                Message = $"Model {modelName} accuracy: {accuracy:P2} " +
                    $"(threshold: 97%). Retraining recommended.",
                Action = "Trigger model retraining pipeline"
            });
        }

        var baseline = await GetBaselineAccuracyAsync(modelName);
        var drift = baseline - accuracy;
        if (drift > 0.02f)
        {
            await _alerts.SendAsync(new Alert
            {
                Severity = AlertSeverity.Warning,
                Title = "Model performance drift detected",
                Message = $"Model {modelName} accuracy dropped by " +
                    $"{drift:P2} from baseline {baseline:P2}"
            });
        }
    }
}
A/B Testing ML Models: New ML model versions are deployed using a canary approach — 5% of traffic routes to the new model while 95% continues with the current version. The platform compares accuracy, latency, and business metrics over 7 days. If the new model performs statistically significantly better (p < 0.05), the rollout progresses to 25%, 50%, and 100%. If any metric regresses, the rollout is automatically rolled back.

23. Cost Estimation

ComponentMonthly CostNotes
API Gateway + Load Balancers$800Global, with WAF
Verification Orchestrator (4 nodes)$2,4004x m5.xlarge
ML Inference (GPU instances)$8,0004x g4dn.xlarge
PostgreSQL (multi-region)$4,0003 regions x 3-node clusters
Redis (multi-region)$1,500Caching + sessions
S3 (encrypted storage)$2,000~50TB + Glacier lifecycle
Kafka (event streaming)$1,500Verification event pipeline
Watchlist data feeds$3,000OFAC, UN, EU, PEP subscriptions
Manual Review Platform$1,000Review dashboard + analyst tools
Monitoring & Logging$1,200Prometheus, Grafana, ELK
Security (KMS, WAF, audit)$800Key management, audit logging
Total~$26,200

Per-Verification Cost

TierML ComputeStorageThird-Party APIsTotal
Tier 1 (Basic)$0.03$0.01$0.00$0.04
Tier 2 (Standard)$0.05$0.01$0.02$0.08
Tier 3 (Enhanced)$0.05$0.01$0.05$0.11
Tier 4 (Full)$0.05$0.01$0.10$0.16

Cost Optimization Strategies

OptimizationSavingsImpact
Spot instances for ML inference~$4,000/month50% of ML cost
S3 Intelligent-Tiering~$600/monthAuto-move old images
Reserved instances (1yr)~$3,000/month30% discount on compute
On-device pre-screening~$2,000/monthReject bad captures early
Optimized Total~$16,600/month37% reduction

24. Testing Strategy

Testing a KYC platform is uniquely challenging because you cannot easily generate "real" identity documents for test purposes, you need to test against a vast variety of document types, and you must verify that fraud detection models catch known attack vectors. The testing strategy spans four levels: unit tests, integration tests, accuracy tests, and end-to-end tests.

Unit Tests

C#
[TestClass]
public class MrzValidatorTests
{
    private readonly MrzValidator _validator = new();

    [TestMethod]
    public void Should_Validate_Correct_US_Passport_MRZ()
    {
        var line1 = "P<USDOE<JOHN<<<<<<<<<<<<<<";
        var line2 = "L898902C36US7004012M1501017<<<<<<00";

        var result = _validator.Validate(line1, line2);

        Assert.IsTrue(result.IsValid);
        Assert.AreEqual("DOE", result.ExtractedData.Surname);
        Assert.AreEqual("JOHN", result.ExtractedData.GivenNames);
        Assert.AreEqual("US", result.ExtractedData.Nationality);
    }

    [TestMethod]
    public void Should_Detect_Invalid_Checksum()
    {
        var line1 = "P<USDOE<JOHN<<<<<<<<<<<<<<";
        var line2 = "L898902C36US7004012M1501017<<<<<<99";

        var result = _validator.Validate(line1, line2);

        Assert.IsFalse(result.IsValid);
        Assert.IsFalse(result.CompositeValid);
    }
}

ML Model Accuracy Tests

C#
[TestClass]
public class FaceMatchingAccuracyTests
{
    private readonly FaceMatchingService _service = new();
    private readonly LabeledDataset _benchmarkDataset;

    [TestMethod]
    public async Task Should_Achieve_99Percent_Accuracy()
    {
        var results = new List<FaceMatchResult>();

        foreach (var pair in _benchmarkDataset.SamePersonPairs)
        {
            var result = await _service.MatchFacesAsync(
                pair.Image1, pair.Image2);
            results.Add(result);
        }

        foreach (var pair in _benchmarkDataset.DifferentPersonPairs)
        {
            var result = await _service.MatchFacesAsync(
                pair.Image1, pair.Image2);
            results.Add(result);
        }

        var truePositives = results.Count(r =>
            r.IsMatch && r.ExpectedMatch);
        var trueNegatives = results.Count(r =>
            !r.IsMatch && !r.ExpectedMatch);

        var accuracy = (float)(truePositives + trueNegatives) /
            results.Count;

        Assert.IsTrue(accuracy >= 0.99f,
            $"Accuracy {accuracy:P2} below 99% threshold");
    }

    [TestMethod]
    public async Task Should_Detect_Photo_Presentation_Attack()
    {
        foreach (var attack in _benchmarkDataset.PhotoAttackSamples)
        {
            var livenessResult = await _service
                .DetectLivenessAsync(attack.Image);

            Assert.IsTrue(!livenessResult.IsLive,
                $"Failed to detect photo attack: {attack.Description}");
        }
    }
}

Test Coverage Targets

ComponentTest TypeCoverage Target
MRZ validationUnit100%
Workflow state machineUnit100%
Risk scoring modelUnit95%+
OCR pipelineIntegration90%+ (200+ document types)
Face matchingAccuracy99%+ on LFW, MegaFace
Liveness detectionAccuracy98%+ attack detection
Watchlist screeningIntegration95%+
End-to-end flowE2EAll happy paths + error paths
Webhook deliveryIntegration99.9%+ delivery
Document Test Dataset: The platform maintains a test dataset of 50,000+ labeled document images covering 200+ document types from 100+ countries. This includes genuine documents, known forgeries, and edge cases (damaged documents, poor lighting, partial captures). The dataset is updated quarterly. Access is restricted to the ML team with a data use agreement — the dataset must never include real user data.

25. Interview Q&A Deep Dive

Q1: How do you handle a situation where the OCR extracts the wrong name from a document?

Answer: OCR errors in name extraction are common, especially with non-Latin scripts, worn documents, or poor capture quality. The system uses multiple extraction strategies in parallel: MRZ extraction (most reliable for passports, uses checksums), zone-based OCR (extracts text from the name zone using language-specific models), and ML field classification (training a model to recognize field types regardless of language). The results from all strategies are compared — if they agree, confidence is high. If they disagree, the system escalates to manual review with all extracted variants presented to the analyst. Additionally, the extracted name is cross-referenced against the watchlist using all variants to maximize matching coverage.

Q2: How do you prevent a deepfake from bypassing liveness detection?

Answer: The defense is multi-layered: (1) Passive liveness analysis examines texture patterns, Moiré artifacts, and depth consistency that deepfakes struggle to replicate perfectly. (2) Active liveness requires real-time challenges (smile, turn head, blink) that pre-recorded deepfakes cannot respond to dynamically. (3) 3D depth analysis (when hardware sensors are available) detects flat deepfake presentations. (4) GAN artifact detection specifically targets the statistical fingerprints left by generative adversarial networks. (5) Temporal consistency analysis checks for frame-to-frame inconsistencies that deepfakes exhibit. No single layer is sufficient — the combination of all five makes it extremely difficult for deepfakes to pass. We also continuously update our detection models with the latest deepfake samples and retrain quarterly.

Q3: How do you handle verification for a user whose document is from a country with no government database for verification?

Answer: Database verification is not available for all countries. When it's not available, the platform relies on the other verification signals: document analysis (template matching, security feature verification, JPEG forensics), biometric matching (face match + liveness), and watchlist/AML screening. The risk scoring model accounts for database availability — a verification without database check receives a slightly higher risk score than one with database confirmation. For high-risk use cases (banking, crypto), we may require additional verification steps (enhanced liveness, address verification, manual review) to compensate for the missing database check. The platform's coverage matrix shows which verification methods are available for each country, allowing clients to set appropriate tier requirements.

Q4: How do you scale the face matching service to handle millions of daily verifications?

Answer: Face matching is computationally intensive — each comparison requires running a CNN forward pass on both images and computing cosine similarity on 512-dimensional embeddings. At 1M verifications/day, that's ~12 QPS sustained, peaking at ~50 QPS. The scaling strategy: (1) Deploy face matching models on GPU instances (g4dn.xlarge or equivalent) with ONNX Runtime for optimized inference. (2) Batch multiple comparisons into single GPU inference calls when possible. (3) Cache face embeddings — if a user resubmits a selfie, reuse the cached ID photo embedding. (4) Auto-scale GPU instances based on inference queue depth. (5) For extreme scale, use model quantization (INT8) to reduce GPU memory and increase throughput by 3-4x with minimal accuracy loss.

Q5: How do you handle a user who submits a genuine document but it's not theirs (stolen identity)?

Answer: This is the core reason for biometric verification. Even if the document is genuine, the face matching step compares the live selfie against the photo on the document. If the selfie doesn't match the ID photo, the verification fails. Liveness detection ensures the selfie is from a live person (not a photo of the document holder). Together, these prevent identity theft even when genuine documents are used. Additional defenses include: behavioral analysis (typing patterns, device usage patterns), address verification (confirming the user knows the address on the ID), and phone/email verification (confirming the user controls the contact channels). For high-risk cases, manual review can examine subtle indicators that automated systems miss.

Q6: How do you handle re-verification when a customer's risk profile changes?

Answer: The re-verification engine runs daily batch scans comparing all active customers against updated watchlist data, adverse media feeds, and risk indicators. When a new match is detected, the system triggers a re-verification workflow: the customer is notified via email/SMS and given a link to complete re-verification. The re-verification flow re-runs all applicable checks (document, biometric, watchlist, AML). If the customer doesn't respond within the grace period (typically 30 days), their account is progressively restricted — first limiting new transactions, then withdrawals, then full freeze. The system tracks re-verification status per customer and produces daily compliance reports showing the re-verification pipeline health.

Q7: How do you balance false acceptance vs. false rejection?

Answer: The balance is configured per client based on their risk appetite and regulatory requirements. A cryptocurrency exchange may accept a 3% false rejection rate to achieve 0.05% false acceptance, while a gig economy platform may accept 0.5% false acceptance to achieve 1% false rejection. The platform provides a configurable threshold system: each verification check (document, face match, liveness, watchlist) has its own threshold, and the composite decision threshold is configurable. The platform monitors both rates in real-time and can auto-tune thresholds within client-defined bounds. When false rejection rates spike (e.g., after a model update), the system alerts operators and can automatically roll back to the previous model version.

Key Numbers to Remember

MetricValue
False Accept Rate (FAR)< 0.1%
False Rejection Rate (FRR)< 2%
Face matching accuracy99.5%+ on benchmarks
Liveness detection accuracy99%+ attack detection
OCR accuracy (MRZ)99%+ character-level
Verification latency (90th percentile)< 30 seconds
Manual review SLA< 4 hours
Document template coverage10,000+ templates, 190+ countries
GDPR erasure SLA72 hours
AML retention period5 years minimum
ML model retraining frequencyQuarterly minimum
Monthly infrastructure cost~$26,200 (optimized: ~$16,600)

Pre-Interview Checklist

  • Understand the full KYC pipeline: document verification, biometrics, watchlist, AML
  • Know how MRZ validation works (checksums, field extraction)
  • Understand liveness detection techniques (passive, active, 3D depth)
  • Be able to explain face matching (CNN embeddings, cosine similarity, threshold calibration)
  • Know watchlist screening challenges (fuzzy name matching, transliteration)
  • Understand AML risk scoring (weighted model, factor weights, decision thresholds)
  • Know the KYC workflow state machine and idempotent step execution
  • Understand tiered verification (Basic → Full, configurable per client)
  • Be familiar with GDPR/CCPA requirements (right to erasure, data minimization)
  • Know the conflict between GDPR erasure and AML retention
  • Understand biometric data security (envelope encryption, key management)
  • Know how to handle document fraud detection (JPEG forensics, ML-based detection)
  • Be able to discuss deepfake countermeasures and the arms race
  • Understand multi-country support and data residency requirements
  • Know the monitoring strategy (system health + business metrics)

Identity Verification & KYC Platform — Senior+ Guide | Ayodhyya