Corebanq Public Docs
Kyc

Description

KYC Screening API

The KYC Screening API provides universal Know Your Customer screening capabilities with support for multiple providers. It implements a database-first strategy for efficient screening and comprehensive search capabilities.

Core API Methods

The KYC API provides three core methods that work universally across all providers:

1. Screen Entity (POST)

POST /v1/kyc/screening

Universal screening method with db-first check strategy. Checks database for existing results first, then performs new screening if needed.

Query Parameters:

  • force (string): Force new screening, bypassing database cache (case-insensitive, accepts 'true', 'TRUE', 'True', etc., default: false)

Request Body:

{
  "entity_type": "individual",
  "individual": {
    "first_name": "John",
    "last_name": "Doe",
    "date_of_birth": "1980-01-01",
    "nationality": "US",
    "address": {
      "country": "US",
      "city": "New York"
    }
  },
  "screening_types": ["sanctions", "peps"],
  "metadata": {
    "source": "customer_onboarding",
    "case_id": "123e4567-e89b-12d3-a456-426614174000"
  }
}

Examples with Force (case-insensitive):

POST /v1/kyc/screening?force=true
POST /v1/kyc/screening?force=TRUE
POST /v1/kyc/screening?force=True

Response:

{
  "request_id": "123e4567-e89b-12d3-a456-426614174000",
  "entity_type": "individual",
  "overall_risk_level": "medium",
  "overall_score": 0.75,
  "screening_results": [
    {
      "screening_type": "sanctions",
      "risk_level": "low",
      "score": 0.0,
      "status": "completed",
      "summary": "No matches found",
      "last_updated": "2025-09-03T18:32:38.854422+02:00"
    },
    {
      "screening_type": "peps",
      "risk_level": "medium",
      "score": 0.75,
      "status": "completed",
      "summary": "1 potential match found",
      "last_updated": "2025-09-03T18:32:38.854422+02:00"
    }
  ],
  "total_matches": 1,
  "has_matches": true,
  "requires_review": true,
  "screened_at": "2025-09-03T18:32:38.396754Z",
  "recommendations": [
    "Review PEP match for potential risk",
    "Conduct additional due diligence"
  ],
  "metadata": {
    "provider": "opensanctions",
    "user_id": "66260c8c-7743-4dfb-84ba-ae9cf6794c9a"
  }
}

2. Get All Screenings (GET)

GET /v1/kyc/screening

Comprehensive search method for existing screening records in the database with advanced query capabilities.

Advanced Query Parameters:

  • search.* - Advanced search operators (see Advanced Search section below)
  • limit (integer): Number of results to return (default: 10, max: 100)
  • offset (integer): Number of results to skip (default: 0)
  • sort (string): Sort fields (comma-separated, prefix with - for descending)
  • stack (string): Group results by field

Example:

GET /v1/kyc/screening?search.entity_type=person&search.has_matches=true&limit=20

3. Get Screening by ID (GET)

GET /v1/kyc/screening/{id}

Retrieve an existing screening record from the database by ID.

Query Parameters:

  • include_matches (string): Include detailed match results (case-insensitive, accepts 'true', 'TRUE', 'True', etc., default: false)
  • include_response (string): Include full KYC provider API response (case-insensitive, accepts 'true', 'TRUE', 'True', etc., default: false)

Examples:

GET /v1/kyc/screening/123e4567-e89b-12d3-a456-426614174000?include_matches=true
GET /v1/kyc/screening/123e4567-e89b-12d3-a456-426614174000?include_matches=TRUE
GET /v1/kyc/screening/123e4567-e89b-12d3-a456-426614174000?include_matches=True&include_response=true

Statistics

Get Screening Statistics

GET /v1/kyc/screening/stats

Get comprehensive statistics about screening operations.

Response:

{
  "total_screenings": 1250,
  "total_matches": 45,
  "match_rate": 0.036,
  "by_entity_type": {
    "person": 800,
    "business": 400,
    "legal": 50
  },
  "by_collection": {
    "default": 600,
    "sanctions": 400,
    "peps": 250
  },
  "by_status": {
    "completed": 1200,
    "pending": 30,
    "failed": 20
  },
  "recent_screenings": [
    {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "entity_type": "person",
      "entity_name": "John Doe",
      "status": "completed",
      "screening_date": "2025-01-02T10:30:00Z",
      "has_matches": true
    }
  ]
}

Advanced Search Capabilities

The GET /v1/kyc/screening endpoint supports advanced search operations using the query package:

Search Operators

All search parameters must be prefixed with search.:

OperatorDescriptionExample
eq (default)Equalsearch.entity_type=person
neNot Equalsearch.status.ne=failed
gtGreater Thansearch.match_count.gt=0
gteGreater Than or Equalsearch.highest_score.gte=0.8
ltLess Thansearch.screening_date.lt=2024-12-31T23:59:59Z
lteLess Than or Equalsearch.highest_score.lte=0.5
inIn Arraysearch.status.in=completed,pending
ninNot In Arraysearch.entity_type.nin=vessel,aircraft
likePattern Matchsearch.entity_name.like=John

Searchable Fields

  • id, entity_type, entity_name, entity_schema, collection
  • status, screening_date, match_count, highest_score, has_matches
  • requested_by, assigned_to, assigned_at, case_id
  • created_at, updated_at

Pagination & Sorting

  • limit (integer): Results per page (default: 10, max: 100)
  • offset (integer): Results to skip (default: 0)
  • sort (string): Sort fields (comma-separated, prefix with - for descending)
  • stack (string): Group results by field

Examples

Basic Search:

GET /v1/kyc/screening?search.entity_type=person&search.has_matches=true

Advanced Search:

GET /v1/kyc/screening?search.match_count.gt=0&search.highest_score.gte=0.8&sort=-screening_date&limit=20

Grouped Results:

GET /v1/kyc/screening?search.has_matches=true&stack=entity_type

Universal API Design

The KYC API is designed with a universal interface that works across all providers. This eliminates the need for provider-specific endpoints and ensures consistency regardless of the underlying KYC provider being used.

Key Benefits:

  • Provider Agnostic: Same API works with OpenSanctions, ComplyAdvantage, LexisNexis, etc.
  • Database-First Strategy: Checks existing data before making external calls
  • Consistent Interface: No need to learn different endpoints for different providers
  • Future Proof: Easy to add new providers without changing the API
  • Simplified Integration: Three core endpoints handle all KYC operations

Entity Types

The API supports the following entity types:

  • individual: Individual persons
  • company: Business entities
  • other: Other entity types

Screening Types

The universal interface supports the following screening types:

  • sanctions: Sanctions and watchlists screening
  • peps: Politically Exposed Persons screening
  • adverse_media: Adverse media and negative news screening
  • identity_verification: Identity verification and validation
  • comprehensive: Comprehensive screening across all types

Data Storage

All screening results are stored in the kyc.screening table with intelligent caching:

  • Database-First Strategy: Checks existing results before external calls
  • Force Option: Use force=true to bypass cache and force new screening
  • Comprehensive Search: Advanced query capabilities for existing records
  • Provider Agnostic: Works with any KYC provider through universal interface

Identity Verification (IDV)

Beyond list screening, the KYC module exposes signatory-focused identity verification backed by Ondato. IDV follows the same transport conventions as screening and is fully wired through , , and .

Endpoints

MethodPathDescription
POST/v1/kyc/{customer_id}/signatories/{signatory_id}/idvCreates a provider session for the referenced signatory. No body is required—the service pulls persona + user metadata inside the transaction.
GET/v1/kyc/{customer_id}/signatories/{signatory_id}/idv?refresh=trueReturns cached status, optionally forcing a refresh when refresh=true (string match). The handler enforces UUID ownership before delegating to the service.

Both endpoints require the standard auth middleware (auth.WrapWithMiddlewares in ). The POST response mirrors models.IDVInitiationResponse, while the GET response returns models.IDVStatusResponse with verification_id, provider session ID, URLs, status, timestamps, and the latest provider payload stored under response_data.

Status Refresh Strategy

GetSignatoryIDV implements a hybrid cache in :

  • Calling GET .../idv without refresh serves cached data unless the session is active (pending or in_progress) and older than kyc.idv.settings.cache_refresh_minutes.
  • Supplying refresh=true bypasses the age check and fetches from Ondato even for terminal statuses.
  • Completed/failed/expired/aborted sessions never auto-refresh, but you can still force-refresh them.
  • If the provider call fails (refreshFromProvider), the service logs a warning and returns the cached snapshot so the endpoint never errors just because Ondato is down.
Session statusCache agerefresh queryBehavior
pending / in_progressTTLfalseAutomatically calls Ondato and persists the update
pending / in_progressanytrueForces provider refresh
completed / failed / expired / abortedanyfalseAlways returns cached data
completed / failed / expired / abortedanytrueForces provider refresh

updated_at in the response reflects the last database write (initiation, webhook, auto-refresh, or poller). completed_at mirrors provider data and is set by webhooks or by applyProviderUpdate whenever Ondato reports a terminal state.

Configuration

All IDV knobs live under kyc.idv.* and ship with documented defaults (). The sample configuration in .samples/config/kyc.yaml looks like:

idv:
  provider: ondato
  ondato:
    api_url: https://idvapi.ondato.com
    token_url: https://id.ondato.com/connect/token
    client_id: your_client_id
    client_secret: your_client_secret
    verification_url: https://idv.ondato.com
    webhook_secret: your_webhook_secret
  settings:
    cache_refresh_minutes: 5
    poller:
      enabled: false
      interval_seconds: 45
      batch_size: 50
      worker_concurrency: 4
      stale_minutes: 5
  urls:
    callback: https://your-domain.com/webhooks/ondato
    success: https://your-domain.com/onboarding/success
    failure: https://your-domain.com/onboarding/retry
  queue:
    driver: rabbitmq
    host: localhost
    routing_key: ondato.*
    name: ondato.webhooks
    listener_route: /webhooks/ondato

Key settings and how the code uses them:

  • Cache refresh TTL (kyc.idv.settings.cache_refresh_minutes): Loaded in NewIDVService. Values ≤0 fall back to constants.KYCIDVDefaultCacheMinutes (5). Active sessions exceeding this age auto-refresh in shouldAutoRefresh.

Set provider: mock plus dummy URLs when you need deterministic integration tests; the service will short-circuit with errs.MsgIDVNotSupported if the driver is missing.

Operational Notes

  • Webhooks are the primary source of truth; the queue consumer rejects malformed payloads (ShouldRetry returns false for permanent failures) and applies updates via applyProviderUpdate.
  • The poller and refresh=true endpoint are safety nets when a webhook is delayed or missed.
  • GetSignatoryIDV always validates {customer_id} ←→ {signatory_id} ownership before returning data, ensuring tenants cannot see each other’s verifications.

On this page