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

# KYC Verification

> Complete guide to implementing Know Your Customer (KYC) verification for members

# KYC Verification

This guide explains how to implement the KYC (Know Your Customer) verification process for members in your application. KYC verification is required before members can receive commission payouts.

## Overview

The MLM Platform supports two KYC providers:

| Provider   | Description                           | Use Case                                       |
| ---------- | ------------------------------------- | ---------------------------------------------- |
| **Manual** | Document upload with admin review     | Default option, full control over verification |
| **Sumsub** | Automated verification via Sumsub SDK | Faster verification, reduced admin workload    |

<Info>
  The KYC provider is configured at the tenant level. Contact support to switch providers.
</Info>

## KYC Verification Flow

The following flowchart illustrates the complete KYC verification process:

```mermaid theme={null}
flowchart TD
    A[Member Initiates KYC] --> B{Call POST /kyc/start}
    B --> C{Provider Type?}
    
    C -->|Manual| D[Receive requiredDocuments list]
    C -->|Sumsub| E[Receive sdkConfig]
    
    D --> F[For each required document]
    F --> G[POST /kyc/documents/upload-url]
    G --> H[Upload file to signed URL]
    H --> I[POST /kyc/documents to record]
    I --> J{More documents?}
    J -->|Yes| F
    J -->|No| K[Status: pending]
    
    E --> L[Initialize Sumsub SDK]
    L --> M[Member completes SDK flow]
    M --> N[Webhook received]
    N --> K
    
    K --> O[Admin reviews submission]
    O --> P{Admin decision}
    
    P -->|Approve| Q[POST /admin/kyc/id/approve]
    Q --> R[Status: approved]
    R --> S[Member can receive payouts]
    
    P -->|Reject| T[POST /admin/kyc/id/reject]
    T --> U[Status: rejected]
    U --> V[Member notified of rejection]
    
    P -->|Request Changes| W[POST /admin/kyc/id/request-resubmit]
    W --> X[Status: resubmit_required]
    X --> Y[Member uploads new documents]
    Y --> K
    
    style A fill:#e1f5fe
    style R fill:#c8e6c9
    style U fill:#ffcdd2
    style X fill:#fff3e0
```

## Implementation Guide

### Step 1: Start KYC Verification

Begin the KYC process by calling the start endpoint:

```bash theme={null}
POST /api/v1/members/{userId}/kyc/start
```

**Response for Manual KYC:**

```json theme={null}
{
  "kycRecordId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "provider": "manual",
  "status": "not_started",
  "uploadUrl": "https://api.mlm-platform.com/api/v1/members/{userId}/kyc/documents",
  "requiredDocuments": [
    {
      "documentType": "government_id_front",
      "label": "Government ID (Front)",
      "description": "Front side of your government-issued ID",
      "required": true,
      "acceptedFormats": ["image/jpeg", "image/png", "application/pdf"]
    },
    {
      "documentType": "government_id_back",
      "label": "Government ID (Back)",
      "description": "Back side of your government-issued ID",
      "required": true,
      "acceptedFormats": ["image/jpeg", "image/png", "application/pdf"]
    },
    {
      "documentType": "selfie",
      "label": "Selfie with ID",
      "description": "A clear photo of yourself holding your ID",
      "required": true,
      "acceptedFormats": ["image/jpeg", "image/png"]
    }
  ],
  "message": "Please upload the required documents to complete verification."
}
```

**Response for Sumsub KYC:**

```json theme={null}
{
  "kycRecordId": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "provider": "sumsub",
  "status": "not_started",
  "sdkConfig": {
    "accessToken": "sbx:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "expiresAt": "2024-01-15T12:30:00Z",
    "flowName": "basic-kyc-flow",
    "applicantId": "65a1b2c3d4e5f6g7h8i9j0"
  },
  "message": "Complete verification using the Sumsub widget."
}
```

### Step 2: Upload Documents (Manual KYC)

For manual KYC, upload each required document using a two-step process:

#### 2a. Get a Signed Upload URL

```bash theme={null}
POST /api/v1/members/{userId}/kyc/documents/upload-url
Content-Type: application/json

{
  "documentType": "government_id_front",
  "fileName": "drivers-license-front.jpg",
  "mimeType": "image/jpeg"
}
```

**Response:**

```json theme={null}
{
  "uploadUrl": "https://storage.supabase.co/...",
  "filePath": "tenant-123/user-456/government_id_front_abc123.jpg",
  "expiresInSeconds": 3600
}
```

#### 2b. Upload the File

Upload the file directly to the signed URL:

```bash theme={null}
PUT {uploadUrl}
Content-Type: image/jpeg

[binary file data]
```

#### 2c. Record the Document

After successful upload, record the document metadata:

```bash theme={null}
POST /api/v1/members/{userId}/kyc/documents
Content-Type: application/json

{
  "documentType": "government_id_front",
  "fileName": "drivers-license-front.jpg",
  "mimeType": "image/jpeg",
  "fileSize": 245678,
  "filePath": "tenant-123/user-456/government_id_front_abc123.jpg"
}
```

<Warning>
  Repeat steps 2a-2c for each document in the `requiredDocuments` array.
</Warning>

### Step 3: Check KYC Status

Poll the status endpoint to track verification progress:

```bash theme={null}
GET /api/v1/members/{userId}/kyc
```

**Response:**

```json theme={null}
{
  "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "status": "pending",
  "provider": "manual",
  "documents": [
    {
      "id": "doc-1",
      "documentType": "government_id_front",
      "fileName": "drivers-license-front.jpg",
      "status": "pending",
      "createdAt": "2024-01-15T10:00:00Z"
    },
    {
      "id": "doc-2",
      "documentType": "government_id_back",
      "fileName": "drivers-license-back.jpg",
      "status": "pending",
      "createdAt": "2024-01-15T10:01:00Z"
    }
  ],
  "createdAt": "2024-01-15T10:00:00Z"
}
```

## KYC Status Values

| Status              | Description                                | Next Action                |
| ------------------- | ------------------------------------------ | -------------------------- |
| `not_started`       | KYC record created, no documents uploaded  | Upload required documents  |
| `pending`           | Documents submitted, awaiting admin review | Wait for admin decision    |
| `approved`          | KYC verification approved                  | Member can receive payouts |
| `rejected`          | KYC verification rejected                  | Review rejection reason    |
| `resubmit_required` | Additional documents or corrections needed | Upload corrected documents |

## Admin Review Process

Administrators review KYC submissions through the Admin Dashboard or API.

### List Pending Reviews

```bash theme={null}
GET /api/v1/admin/kyc/pending
```

### View KYC Details

```bash theme={null}
GET /api/v1/admin/kyc/{kycId}
```

### Download Document for Review

```bash theme={null}
GET /api/v1/admin/kyc/documents/{documentId}
```

### Approve KYC

```bash theme={null}
POST /api/v1/admin/kyc/{kycId}/approve
Content-Type: application/json

{
  "notes": "All documents verified successfully"
}
```

### Reject KYC

```bash theme={null}
POST /api/v1/admin/kyc/{kycId}/reject
Content-Type: application/json

{
  "reason": "ID document is expired. Please upload a valid, non-expired ID."
}
```

### Request Resubmission

```bash theme={null}
POST /api/v1/admin/kyc/{kycId}/request-resubmit
Content-Type: application/json

{
  "reason": "Selfie photo is blurry. Please upload a clearer photo.",
  "requiredDocuments": ["selfie"]
}
```

## OCR-Extracted Data

For supported document types, the platform automatically extracts data using OCR:

| Document Type         | Extracted Fields                      |
| --------------------- | ------------------------------------- |
| `government_id_front` | Full name, date of birth, address     |
| `government_id_back`  | Address (if present)                  |
| `passport`            | Full name, date of birth, nationality |
| `proof_of_address`    | Address, document date                |

Extracted data is available in the admin review interface and can be edited before approval.

## Best Practices

<CardGroup cols={2}>
  <Card title="Validate Before Upload" icon="check">
    Check file size and format on the client before uploading to avoid rejected uploads.
  </Card>

  <Card title="Show Progress" icon="spinner">
    Display upload progress and status updates to keep members informed.
  </Card>

  <Card title="Handle Errors Gracefully" icon="triangle-exclamation">
    Provide clear error messages when uploads fail or documents are rejected.
  </Card>

  <Card title="Secure File Handling" icon="lock">
    Never store KYC documents on your own servers. Use the signed URLs provided.
  </Card>
</CardGroup>

## Error Handling

| Error Code | Description                                      | Resolution                           |
| ---------- | ------------------------------------------------ | ------------------------------------ |
| `400`      | Invalid request (missing fields, invalid format) | Check request body matches schema    |
| `401`      | Unauthorized                                     | Verify API key is valid              |
| `403`      | Forbidden                                        | Ensure user belongs to your tenant   |
| `404`      | KYC record or document not found                 | Verify the ID is correct             |
| `409`      | KYC already in progress or completed             | Check current status before starting |
| `413`      | File too large                                   | Reduce file size (max 10MB)          |

## Webhooks

Configure webhooks to receive real-time notifications when KYC status changes:

| Event                   | Description                             |
| ----------------------- | --------------------------------------- |
| `kyc.submitted`         | Member submitted all required documents |
| `kyc.approved`          | Admin approved the KYC verification     |
| `kyc.rejected`          | Admin rejected the KYC verification     |
| `kyc.resubmit_required` | Admin requested document resubmission   |

See the [Webhooks Guide](/guides/webhooks) for configuration details.

## Complete Code Example

Here's a complete example of implementing KYC document upload in JavaScript:

```javascript theme={null}
async function uploadKycDocuments(userId, files) {
  const apiKey = process.env.MLM_API_KEY;
  const baseUrl = 'https://api.mlm-platform.com/api/v1';
  
  // Step 1: Start KYC
  const startResponse = await fetch(
    `${baseUrl}/members/${userId}/kyc/start`,
    {
      method: 'POST',
      headers: { 'x-tenant-api-key': apiKey }
    }
  );
  const { kycRecordId, requiredDocuments } = await startResponse.json();
  
  // Step 2: Upload each document
  for (const doc of requiredDocuments) {
    const file = files[doc.documentType];
    if (!file) continue;
    
    // 2a: Get signed URL
    const urlResponse = await fetch(
      `${baseUrl}/members/${userId}/kyc/documents/upload-url`,
      {
        method: 'POST',
        headers: {
          'x-tenant-api-key': apiKey,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          documentType: doc.documentType,
          fileName: file.name,
          mimeType: file.type
        })
      }
    );
    const { uploadUrl, filePath } = await urlResponse.json();
    
    // 2b: Upload file
    await fetch(uploadUrl, {
      method: 'PUT',
      headers: { 'Content-Type': file.type },
      body: file
    });
    
    // 2c: Record document
    await fetch(
      `${baseUrl}/members/${userId}/kyc/documents`,
      {
        method: 'POST',
        headers: {
          'x-tenant-api-key': apiKey,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          documentType: doc.documentType,
          fileName: file.name,
          mimeType: file.type,
          fileSize: file.size,
          filePath
        })
      }
    );
  }
  
  return kycRecordId;
}
```

## Next Steps

* [API Reference: Member KYC](/api-reference/kyc/start-kyc-verification) - Complete API documentation
* [Webhooks Guide](/guides/webhooks) - Set up KYC status notifications
* [Sandbox Testing](/guides/sandbox-testing) - Test KYC flows in sandbox mode
