Skip to content

tagshelfsrl/2face-workbench

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

1 Commit
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

2FACE API KYC Demo

A Python demonstration script showcasing the complete Know Your Customer (KYC) flow using the 2FACE API. This script provides a practical, developer-friendly example of how to integrate document validation, information extraction, and face comparison capabilities.

🎯 Overview

This demo implements a complete KYC verification workflow:

  1. Session Management - Creates and manages API sessions
  2. Document Validation - Validates that an image contains a valid CEDULA (Dominican ID card)
  3. Information Extraction - Extracts personal information from the document
  4. Face Comparison - Compares a selfie against the document photo
  5. Asynchronous Processing - Handles async jobs with intelligent polling

✨ Features

  • Modular Architecture - Clean, reusable functions for each API endpoint
  • Environment-Based Config - Easy configuration via .env file
  • Robust Error Handling - Comprehensive error messages and graceful failures
  • Async Job Polling - Automatic polling with configurable timeouts
  • Detailed Logging - Progress tracking and debugging information
  • Type Hints - Full type annotations for better IDE support

πŸ“‹ Prerequisites

  • Python 3.7 or higher
  • Valid 2FACE API credentials and endpoint URL
  • Test images (CEDULA and selfie)

πŸš€ Quick Start

1. Install Dependencies

pip install -r requirements.txt

2. Configure Environment

Copy the example environment file and fill in your values:

cp .env.example .env

Edit .env with your configuration:

TWOFACE_API_URL=https://your-api-url.com
CEDULA_IMAGE_PATH=/path/to/cedula.jpg
SELFIE_IMAGE_PATH=/path/to/selfie.jpg

3. Run the Demo

python kyc_demo.py

πŸ“– Detailed Usage

Environment Variables

Variable Required Description
TWOFACE_API_URL βœ… Yes Base URL for the 2FACE API
TWOFACE_API_KEY βœ… Yes API key for authentication (create via admin panel)
CEDULA_IMAGE_PATH βœ… Yes Path to CEDULA image file
SELFIE_IMAGE_PATH βœ… Yes Path to selfie image file
LOG_LEVEL ❌ No Logging level (default: INFO)
MAX_JOB_WAIT ❌ No Max wait time for jobs in seconds (default: 120)
POLL_INTERVAL ❌ No Polling interval in seconds (default: 2)
LOG_JOB_RESULTS ❌ No Set to true to print full JSON results of jobs

Image Requirements

CEDULA Image:

  • Clear, well-lit photo of the front of a Dominican ID card
  • Supported formats: JPG, JPEG, PNG
  • Recommended: Minimum 800x600 resolution

Selfie Image:

  • Clear frontal face photo
  • Good lighting, no shadows
  • Face should be clearly visible
  • Supported formats: JPG, JPEG, PNG

πŸ”„ API Flow

The script executes the following steps:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 1. Create Session                                           β”‚
β”‚    POST /session                                            β”‚
β”‚    β†’ Returns: session_id                                    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 2. Validate Document Type                                   β”‚
β”‚    POST /documents/validate-document-type                   β”‚
β”‚    β†’ Returns: job_id                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 3. Poll Job Status                                          β”‚
β”‚    GET /jobs/{job_id}                                       β”‚
β”‚    β†’ Wait until: status = 2 (Succeded)                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 4. Fetch Document Information                               β”‚
β”‚    POST /documents/fetch-document-data                      β”‚
β”‚    β†’ Returns: job_id                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 5. Poll Job Status                                          β”‚
β”‚    GET /jobs/{job_id}                                       β”‚
β”‚    β†’ Wait until: status = 2 (Succeded)                      β”‚
β”‚    β†’ Extract: document_id                                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 6. Compare Face to Document                                 β”‚
β”‚    POST /faces/compare-to-document                          β”‚
β”‚    β†’ Returns: job_id                                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 7. Poll Job Status                                          β”‚
β”‚    GET /jobs/{job_id}                                       β”‚
β”‚    β†’ Wait until: status = 2 (Succeded)                      β”‚
β”‚    β†’ Returns: similarity score (>50% = match)               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                            ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 8. Close Session                                            β”‚
β”‚    POST /session/close                                      β”‚
β”‚    β†’ status: SUCCESS or FAILED                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”§ Using as a Library

You can also import and use the KYCClient class in your own code:

from kyc_demo import KYCClient, KYCAPIError

# Initialize client
client = KYCClient("https://api.2face.example.com")

try:
    # Create session
    session_id = client.create_session("SIGNUP")
    
    # Validate document
    job_id = client.validate_document_type("/path/to/cedula.jpg")
    result = client.poll_job_status(job_id)
    
    # Fetch document data
    job_id = client.fetch_document_data("/path/to/cedula.jpg")
    result = client.poll_job_status(job_id)
    
    # Compare face
    job_id = client.compare_face_to_document("/path/to/selfie.jpg", "DOC123")
    result = client.poll_job_status(job_id)
    
    # Close session
    client.close_session("SUCCESS")
    
except KYCAPIError as e:
    print(f"Error: {e}")
    if client.session_id:
        client.close_session("FAILED")

πŸ“ Example Output

2025-12-01 21:56:00 - INFO - ======================================================================
2025-12-01 21:56:00 - INFO - Starting KYC Flow
2025-12-01 21:56:00 - INFO - ======================================================================

2025-12-01 21:56:00 - INFO - [Step 1/6] Creating session...
2025-12-01 21:56:01 - INFO - βœ“ Session created successfully: abc123xyz

2025-12-01 21:56:01 - INFO - [Step 2/6] Validating document type...
2025-12-01 21:56:02 - INFO - βœ“ Document validation job created: job_456

2025-12-01 21:56:02 - INFO - [Step 3/6] Polling document validation job...
2025-12-01 21:56:02 - INFO -   Poll #1 (0.5s): Status = PROCESSING
2025-12-01 21:56:04 - INFO -   Poll #2 (2.5s): Status = COMPLETED
2025-12-01 21:56:04 - INFO - βœ“ Job completed successfully

... [additional steps] ...

2025-12-01 21:56:15 - INFO - ======================================================================
2025-12-01 21:56:15 - INFO - KYC Flow Completed Successfully!
2025-12-01 21:56:15 - INFO - ======================================================================

2025-12-01 21:56:15 - INFO - πŸ“„ Document Validation Result:
2025-12-01 21:56:15 - INFO -   {'status': 'COMPLETED', 'isValid': True}

2025-12-01 21:56:15 - INFO - πŸ“‹ Document Information:
2025-12-01 21:56:15 - INFO -   {'documentId': '00112345678', 'firstName': 'Juan', ...}

2025-12-01 21:56:15 - INFO - πŸ‘€ Face Comparison Result:
2025-12-01 21:56:15 - INFO -   Similarity: 95.3
2025-12-01 21:56:15 - INFO -   Match: True

2025-12-01 21:56:15 - INFO - βœ… KYC Demo completed successfully!

πŸ› οΈ Troubleshooting

Connection Errors

  • Verify TWOFACE_API_URL is correct
  • Check network connectivity
  • Ensure API endpoint is accessible

File Not Found

  • Verify image paths are absolute paths
  • Check file permissions
  • Ensure files exist at specified locations

Job Timeout

  • Increase MAX_JOB_WAIT in environment variables
  • Check if API is experiencing high load
  • Verify images are not corrupted

Validation Failures

  • Ensure CEDULA image is clear and well-lit
  • Check that document is fully visible in image
  • Verify correct document type is specified

πŸ“š API Documentation

For detailed API documentation, refer to the 2FACE API Postman collection.

Key Endpoints

  • POST /session - Create session
  • POST /session/close - Close session
  • POST /documents/validate-document-type - Validate document type
  • POST /documents/fetch-document-data - Extract document information
  • POST /faces/compare-to-document - Compare face to document
  • GET /jobs/{jobId} - Get job status

Authentication

Per the official 2FACE documentation, the API provides two authentication methods:

1. App API Key

  • Preferred method for unattended production applications
  • API keys created via company applications admin panel
  • Passed as HTTP header: Authorization: <api_key> (NOT a bearer token)
  • Used for endpoints that don't require a session

2. Session Token

  • Required for session-based KYC flow endpoints
  • Created via POST /session endpoint
  • Passed as HTTP header: X-Tagshelf-Session: <token>
  • Used INSTEAD OF the API key (not in addition to)

How This Script Handles Authentication:

  • Uses API key (Authorization header) for:
    • Session creation (POST /session)
    • Job polling (GET /jobs/{jobId})
  • Uses session token (X-Tagshelf-Session header) for KYC flow endpoints:
    • Document validation, data extraction, face comparison
  • Only one authentication method is used per request

Security Note: Don't expose your API key in client applications. API keys are meant for backend servers.

🀝 Contributing

This is a demonstration script. Feel free to extend it for your specific use case.

πŸ“„ License

This demo script is provided as-is for educational and integration purposes.

πŸ‘¨β€πŸ’» Author

Senior Software Developer - 2025

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages