> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vultlocal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# KYC Validation

> OCR extraction, fraud detection, and document validation for KYC

# KYC Validation

Agent-TS includes multi-layer KYC document validation with OCR extraction, OpenAI Vision verification, and fraud detection for Sierra Leone National ID cards.

## Validation Pipeline

```mermaid theme={null}
graph LR
    IMG[Image Upload] --> COMP[Compress Image]
    COMP --> OCR[OCR Extraction]
    OCR --> VIS[Vision Validation]
    VIS --> FRAUD[Fraud Detection]
    FRAUD --> CROSS[Cross-Validation]
    CROSS --> S3[S3 Upload]
    S3 --> GW[Update Gateway]
```

## OCR Service

The OCR service uses Tesseract.js to extract text and compute confidence scores.

### Extracted Fields

For Sierra Leone National ID cards:

| Field                    | Example           |
| ------------------------ | ----------------- |
| Personal ID Number (NIN) | `NIN: 1234567890` |
| Surname                  | `KAMARA`          |
| First Name               | `IBRAHIM`         |
| Middle Name              | `MOHAMED`         |
| Date of Birth            | `15/03/1990`      |
| Gender                   | `MALE`            |
| Height                   | `1.75m`           |
| Date of Expiry           | `15/03/2030`      |

### Usage

```typescript theme={null}
import { ocrService } from './ocr-service';

const result = await ocrService.extractTextFromImage(base64Image);

console.log('Extracted NIN:', result.extractedData.nin);
console.log('Full Name:', result.extractedData.fullName);
console.log('Confidence:', result.confidence);
console.log('Raw Text:', result.rawText);
```

### OCR Result Interface

```typescript theme={null}
interface OCRResult {
  success: boolean;
  rawText: string;
  confidence: number;  // 0-100
  extractedData: {
    nin?: string;
    surname?: string;
    firstName?: string;
    middleName?: string;
    fullName?: string;
    dateOfBirth?: string;
    gender?: string;
    height?: string;
    expiryDate?: string;
  };
  fraudIndicators: string[];
}
```

## Vision API Validation

The ID Card Validator uses OpenAI's Vision API for document authenticity checks.

### Validation Checks

<CardGroup cols={2}>
  <Card title="Document Type" icon="id-card">
    Verifies the image is a valid Sierra Leone National ID
  </Card>

  <Card title="Photo Presence" icon="user">
    Confirms a clear photo is visible on the document
  </Card>

  <Card title="Official Appearance" icon="building-government">
    Checks for official government styling and elements
  </Card>

  <Card title="Text Readability" icon="text">
    Ensures text is legible and not obscured
  </Card>
</CardGroup>

### Usage

```typescript theme={null}
import { idCardValidator } from './id-card-validator';

// Validate single side
const result = await idCardValidator.validateIDCard(base64Image, 'front');

if (result.fraudDetected) {
  console.log('Fraud indicators:', result.fraudIndicators);
}

// Validate both sides with cross-checking
const validation = await idCardValidator.validateBothSides(frontImage, backImage);

if (!validation.crossValidation.consistent) {
  console.log('Issues:', validation.crossValidation.issues);
}
```

## Fraud Detection

### Fraud Indicators

The system detects multiple fraud patterns:

| Indicator                 | Description                                    |
| ------------------------- | ---------------------------------------------- |
| `LOW_OCR_CONFIDENCE`      | OCR confidence below 60%                       |
| `MISSING_OFFICIAL_HEADER` | "REPUBLIC OF SIERRA LEONE" not found           |
| `MISSING_ID_HEADER`       | "NATIONAL IDENTITY CARD" not found             |
| `SUSPICIOUS_TEXT_PATTERN` | Contains "photoshop", "edited", "sample", etc. |
| `REPEATING_ID_PATTERN`    | ID number like "11111111" or "12341234"        |
| `FRONT_BACK_MISMATCH`     | Name/ID differs between sides                  |
| `MISSING_CRITICAL_DATA`   | Required fields not extracted                  |
| `CONFIDENCE_MISMATCH`     | Large difference between front/back confidence |

### Suspicious Text Patterns

```typescript theme={null}
const SUSPICIOUS_PATTERNS = [
  'photoshop',
  'edited',
  'sample',
  'template',
  'test',
  'demo',
  'fake',
  'copy'
];
```

### Cross-Validation

When both sides are provided, the system performs cross-validation:

```typescript theme={null}
interface CrossValidation {
  consistent: boolean;
  issues: string[];
  frontConfidence: number;
  backConfidence: number;
  nameMatch: boolean;
  idMatch: boolean;
}
```

## Complete Validation Flow

### Single Image Upload

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant A as Agent
    participant OCR as OCR Service
    participant V as Vision Validator
    participant S3 as S3 Uploader

    U->>A: [Image] "Front of my ID"
    A->>OCR: Extract text
    OCR-->>A: OCR result + confidence
    A->>V: Validate with Vision API
    V-->>A: Validation result
    
    alt Fraud Detected
        A-->>U: "Issues found: [list]"
    else Valid Document
        A->>S3: Upload image
        S3-->>A: s3:// URI
        A-->>U: "Front uploaded. Send back."
    end
```

### KYC Upgrade (Both Sides)

```mermaid theme={null}
sequenceDiagram
    participant U as User
    participant A as Agent
    participant V as Vision Validator
    participant S3 as S3 Uploader
    participant G as Gateway

    U->>A: "Complete my KYC"
    A->>V: Cross-validate front + back
    V-->>A: Cross-validation result
    
    alt Inconsistent
        A-->>U: "Mismatch found: [issues]"
    else Consistent
        A->>S3: Upload both images
        S3-->>A: s3:// URIs
        A->>G: Update KYC status
        G-->>A: Success
        A-->>U: "KYC upgrade complete!"
    end
```

## Configuration

### OCR Settings

```typescript theme={null}
// ocr-service.ts
const ocrConfig = {
  lang: 'eng',
  oem: 1,  // LSTM only
  psm: 3,  // Fully automatic page segmentation
};
```

### Confidence Thresholds

| Threshold                 | Value | Purpose                        |
| ------------------------- | ----- | ------------------------------ |
| Minimum OCR confidence    | 60%   | Below this triggers fraud flag |
| Warning OCR confidence    | 75%   | Below this shows warning       |
| Cross-validation mismatch | 20%   | Difference between front/back  |

## Image Requirements

For best results, KYC images should:

<AccordionGroup>
  <Accordion title="Image Quality">
    * Minimum resolution: 800x600 pixels
    * Clear, in-focus image
    * Good lighting without glare
    * No blur or motion artifacts
  </Accordion>

  <Accordion title="Document Positioning">
    * ID card fills 70-80% of frame
    * All edges visible
    * No fingers covering text
    * Flat surface (no curves)
  </Accordion>

  <Accordion title="File Format">
    * JPEG or PNG format
    * Maximum file size: 10MB
    * Base64 encoded with data URI prefix
  </Accordion>
</AccordionGroup>

## Error Handling

```typescript theme={null}
// Handle validation errors gracefully
try {
  const result = await idCardValidator.validateIDCard(image, 'front');
  
  if (!result.success) {
    return {
      success: false,
      userMessage: 'Could not validate your ID. Please try again.'
    };
  }
  
  if (result.fraudDetected) {
    return {
      success: false,
      userMessage: `Document issues: ${result.fraudIndicators.join(', ')}`,
      requiresResubmission: true
    };
  }
  
  // Proceed with upload
} catch (error) {
  logger.error('KYC validation failed', { error });
  return {
    success: false,
    userMessage: 'Validation failed. Please try again later.'
  };
}
```

## S3 Storage

Validated documents are stored in S3:

```typescript theme={null}
// s3-uploader.ts
const uploadResult = await s3Uploader.uploadKYCDocument({
  userId: context.userId,
  side: 'front',
  image: base64Image,
  extractedData: ocrResult.extractedData
});

// Returns: s3://olive-kyc-documents/kyc/user123/front_2024-01-15.jpg
```

### Pre-signed URLs

For admin access to KYC documents:

```typescript theme={null}
const url = await s3Uploader.getPresignedUrl(s3Uri, 3600); // 1 hour
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="webhook" href="/agent-ts/webhooks">
    WhatsApp integration for receiving images
  </Card>

  <Card title="Tools Reference" icon="wrench" href="/agent-ts/tools">
    KYC tool definitions
  </Card>
</CardGroup>
