Skip to main content

Installation

pip install verilock
Requires Python 3.9+. The SDK uses httpx under the hood for both sync and async support.

Configuration

from verilock import Verilock

client = Verilock(
    api_key="qi_live_...",              # or set VERILOCK_API_KEY env var
    base_url="https://verilock.io/api/v1", # optional
    timeout=30,                          # optional, seconds (default: 30)
    max_retries=2,                       # optional, retries on 429/5xx
)
Use a qi_test_ key during development. Test keys return simulated results and are free to use.

Quick Start

from verilock import Verilock

with Verilock(api_key="qi_live_...") as client:
    # Create a KYC session
    session = client.sessions.create({
        "applicant_email": "john@example.com",
        "applicant_name": "John Doe",
        "redirect_url": "https://example.com/callback",
    })

    # Redirect the user to complete verification
    print(session["session_url"])

    # Later, retrieve the result
    result = client.sessions.retrieve(session["id"])
    print(result["status"])  # 'approved' | 'rejected' | 'pending' | ...

KYC Sessions

Create a session

session = client.sessions.create({
    "applicant_email": "jane@example.com",
    "applicant_name": "Jane Smith",
    "redirect_url": "https://example.com/done",
})
# session["session_url"] -> hosted verification link

List sessions

response = client.sessions.list(status="approved", page=1, per_page=25)
for item in response["data"]:
    print(f"{item['id']}: {item['status']}")

Retrieve a session

session = client.sessions.retrieve("sess_abc123")

Upload a document

with open("id_front.jpg", "rb") as f:
    client.sessions.upload_document(
        session_id="sess_abc123",
        file=f.read(),
        side="front",
        document_type="passport",
    )

Upload a selfie

with open("selfie.jpg", "rb") as f:
    client.sessions.upload_selfie(session_id="sess_abc123", file=f.read())

Submit for evaluation

result = client.sessions.submit("sess_abc123")
print(result["status"])  # 'processing'
Call submit() only after all required documents and selfie have been uploaded. The session enters asynchronous processing and you will receive a webhook when it completes.

AML Screening

Screen a person

result = client.aml.screen({
    "name": "John Doe",
    "date_of_birth": "1990-01-15",
    "nationality": "US",
})

if result["status"] == "match":
    print(f"Found {result['matches_found']} matches")

Retrieve a screening

screening = client.aml.retrieve("aml_abc123")

Submit a decision

client.aml.decide("aml_abc123", {
    "decision": "false_positive",
    "reason": "Name similarity only, different date of birth.",
})

Transaction Monitoring

Screen a transaction

result = client.transactions.screen({
    "transaction_ref": "TX-001",
    "sender_name": "Alice Corp",
    "receiver_name": "Bob Ltd",
    "amount": 15000,
    "currency": "USD",
})

if result["risk_level"] == "high":
    print(f"{result['alerts_count']} alerts triggered")

Batch screening

batch = client.transactions.screen_batch({
    "transactions": [
        {"transaction_ref": "TX-002", "sender_name": "Alice", "receiver_name": "Bob", "amount": 500, "currency": "EUR"},
        {"transaction_ref": "TX-003", "sender_name": "Carol", "receiver_name": "Dave", "amount": 12000, "currency": "USD"},
    ],
})

List, retrieve, and decide

response = client.transactions.list(risk_level="high")

detail = client.transactions.retrieve("txn_abc123")

client.transactions.decide("txn_abc123", {
    "decision": "approve",
    "reason": "Verified sender identity manually.",
})

Premium Features

Premium features require a paid plan. Calls made without an active subscription raise an InsufficientBalanceError.
# Biometric face authentication
match = client.biometric.verify(session_id="sess_abc123", selfie=selfie_bytes)

# Government database validation
db_check = client.database.validate(document_number="AB123456", country="US")

# 1:N face duplicate detection
duplicates = client.face_search.search(selfie=selfie_bytes)

# Crypto wallet compliance screening
wallet_result = client.wallet.screen(address="0xabc...", chain="ethereum")

# Reusable KYC credentials
credential = client.credentials.issue(session_id="sess_abc123")

# Age verification from selfie
age = client.age_verify.verify(selfie=selfie_bytes, min_age=18)

Error Handling

All SDK errors extend VerilockError. Use specific classes for granular handling.
from verilock.errors import (
    VerilockError,
    AuthenticationError,
    InsufficientBalanceError,
    NotFoundError,
    ValidationError,
    RateLimitError,
)

try:
    session = client.sessions.create({
        "applicant_email": "john@example.com",
        "redirect_url": "https://example.com/callback",
    })
except InsufficientBalanceError as e:
    print(f"Balance: {e.balance}, required: {e.required}")
except ValidationError as e:
    print(f"Field errors: {e.errors}")
except RateLimitError as e:
    print(f"Retry after {e.retry_after}s")
except AuthenticationError:
    print("Invalid API key")
except NotFoundError:
    print("Resource not found")
except VerilockError as e:
    print(f"API error [{e.code}]: {e.message}")

Context Managers

Both the sync and async clients support context managers that automatically close the underlying httpx connection pool.
from verilock import Verilock

with Verilock(api_key="qi_live_...") as client:
    session = client.sessions.create({...})
# Connection pool is closed automatically
Using context managers is recommended to avoid resource leaks. Alternatively, call client.close() (or await client.close() for async) when you are done.