Skip to main content

Overview

To upgrade users to higher KYC levels (L2+), you need to upload supporting documents such as ID images, proof of address, and source of funds documentation.
Documents must be clear, unaltered images in JPG, PNG, or PDF format, maximum 10MB per file.

Document Types

Person Documents

Government-issued ID with photo
  • PASSPORT - Passport
  • DRIVER_LICENSE - Driver’s license
  • NUIP - Colombian ID
  • INE - Mexican electoral ID
  • IFE - Mexican electoral ID (old)
  • RFC - Mexican tax ID
  • SSN - US Social Security
  • CURP - Mexican population registry
  • CPF - Brazilian tax ID
  • DNI - National ID
  • DUI - Unique ID document
Requirements:
  • Front image (always required)
  • Back image (if applicable)
  • Clear, readable text
  • All corners visible
  • No glare or shadows

Company Documents

  • NIT - Colombian tax ID
  • PROOF_OF_COMPANY_FORMATION - Formation documents
  • ARTICLES_OF_INCORPORATION - Incorporation articles
  • INCORPORATION_DOCUMENTS - Legal documents
  • KYB_REPORT - Know Your Business report
  • OTHER - Other business documents

Uploading Person Documents

POST /api/v2/users/person/document
Content-Type: multipart/form-data
const uploadDocument = async (userId, documentType, frontFile, backFile = null) => {
  const formData = new FormData();
  formData.append('userId', userId);
  formData.append('documentType', documentType);
  formData.append('frontDocument', frontFile);
  
  if (backFile) {
    formData.append('backDocument', backFile);
  }
  
  const response = await fetch(
    'https://teste-94u93qnn.uc.gateway.dev/api/v2/users/person/document',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`
      },
      body: formData
    }
  );
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(`Upload failed: ${error.message}`);
  }
  
  return await response.json();
};

// Usage
const frontImage = new File([blob], 'passport-front.jpg', { type: 'image/jpeg' });
await uploadDocument(userId, 'PASSPORT', frontImage);

Uploading Company Documents

POST /api/v2/users/company/document
Content-Type: multipart/form-data
const uploadCompanyDocument = async (userId, documentType, documentFile) => {
  const formData = new FormData();
  formData.append('userId', userId);
  formData.append('documentType', documentType);
  formData.append('frontDocument', documentFile);
  
  const response = await fetch(
    'https://teste-94u93qnn.uc.gateway.dev/api/v2/users/company/document',
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${accessToken}`
      },
      body: formData
    }
  );
  
  return await response.json();
};

Document Guidelines

Photo Quality

Image Requirements

Good:
  • Clear, focused image
  • All text readable
  • All corners visible
  • Good lighting
  • Original color
  • Minimum 300 DPI
Bad:
  • Blurry or out of focus
  • Glare or shadows
  • Cropped corners
  • Black and white copy
  • Screenshots
  • Low resolution
Accepted Formats:
  • JPEG/JPG (recommended)
  • PNG
  • PDF (for statements/letters)
Size Limits:
  • Maximum: 10 MB per file
  • Minimum: 100 KB
  • Recommended: 1-3 MB
  • No edits or alterations
  • Current/valid documents only
  • Complete document visible
  • Original documents (no photocopies)
  • Color images preferred
  • Recent photos (within 6 months for proof of address)

Taking Good Photos

1

Use Good Lighting

Natural light works best. Avoid flash.
2

Flat Surface

Place document on flat, contrasting surface
3

Align Properly

Document should be straight and centered
4

Fill Frame

Document should occupy most of the image
5

Check Quality

Verify all text is readable before uploading

Client-Side Validation

Validate documents before upload:
const validateDocument = (file) => {
  const errors = [];
  
  // File size
  const maxSize = 10 * 1024 * 1024; // 10MB
  if (file.size > maxSize) {
    errors.push('File too large. Maximum 10MB.');
  }
  
  if (file.size < 100 * 1024) {
    errors.push('File too small. Minimum 100KB.');
  }
  
  // File type
  const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'];
  if (!allowedTypes.includes(file.type)) {
    errors.push('Invalid file type. Use JPG, PNG, or PDF.');
  }
  
  // Image dimensions (for images)
  if (file.type.startsWith('image/')) {
    const img = new Image();
    img.src = URL.createObjectURL(file);
    
    img.onload = () => {
      if (img.width < 800 || img.height < 600) {
        errors.push('Image resolution too low. Minimum 800x600.');
      }
    };
  }
  
  return errors;
};

Tracking Upload Status

Monitor document processing:
const trackDocumentStatus = async (userId) => {
  // Get user details
  const user = await fetch(`/api/v2/users/${userId}`, {
    headers: { 'Authorization': `Bearer ${token}` }
  }).then(r => r.json());
  
  console.log('Current Status:', user.status);
  console.log('Access Level:', user.accessLevel);
  console.log('Note:', user.note);
  
  // If pending, check compliance URL
  if (user.status === 'PENDING') {
    console.log('Complete KYC at:', user.complianceUrl);
  }
  
  return user;
};

Webhooks for Document Updates

Subscribe to USER events to get notified:
{
  "event": "user.kyc_submitted",
  "data": {
    "userId": "user-id",
    "documentsSubmitted": ["PASSPORT", "PROVE_OF_ADDRESS_UTILITY_BILL"],
    "status": "PENDING"
  }
}
{
  "event": "user.kyc_approved",
  "data": {
    "userId": "user-id",
    "previousLevel": "L1",
    "newLevel": "L2",
    "status": "ACTIVE"
  }
}

Handling Rejections

If documents are rejected:
{
  "event": "user.kyc_rejected",
  "data": {
    "userId": "user-id",
    "reason": "Document image quality insufficient",
    "rejectedDocuments": ["PASSPORT"],
    "status": "REJECTED"
  }
}
Action Required:
  1. Notify user of rejection
  2. Explain specific issue from reason
  3. Request resubmission
  4. Provide upload guidelines
  5. Monitor resubmission

Document Retention

Documents are securely stored and retained per regulatory requirements. Users can request deletion per GDPR/privacy laws.

Best Practices

  • Show real-time upload progress
  • Preview images before submit
  • Provide photo guidelines
  • Allow retake if quality poor
  • Save progress between steps
  • Use device camera for capture
  • Optimize image size automatically
  • Compress before upload
  • Handle network interruptions
  • Show data usage estimates
  • Validate files client-side first
  • Show specific error messages
  • Allow easy retry
  • Preserve form data on failure
  • Log upload errors

Compliance URL Alternative

Instead of handling document uploads yourself, redirect users to KillB’s compliance URL:
const user = await createUser(userData);

// Redirect to KillB's KYC portal
window.location.href = user.complianceUrl;
Benefits:
  • KillB handles entire KYC flow
  • Built-in document capture
  • Automatic verification
  • Mobile-optimized
  • Multi-language support
  • Liveness detection included
Using the compliance URL is the easiest integration path. Users complete KYC on KillB’s portal and you receive webhook notifications.

Next Steps