KYC Compliance Flow
This guide explains how to integrate the KYC compliance system using both webhooks (push) and the Compliance Status API (pull).
Overview
The KYC system provides two complementary mechanisms:
- Webhooks (Push): Real-time notifications when KYC state changes
- Compliance Status API (Pull): On-demand status with actionable guidance
Use webhooks for real-time updates; use the API to get current state and determine next steps.
Integration Paths
Connect Financial supports two KYC integration strategies:
| Strategy | Description | Best For |
|---|---|---|
| Standard (CF_KYC) | Users complete identity verification via Connect Financial's SDK | Most integrations |
| External KYC | You handle verification with your own KYC provider | Clients with existing KYC infrastructure |
This guide covers the standard flow first. See External KYC Integration if you manage your own KYC process.
Webhook Events
Subscribe to these events via the Webhook API:
| Event | When it fires | What it means |
|---|---|---|
CUSTOMER_KYC_STARTED | POST /v1/compliance/kyc called | KYC process initiated |
CUSTOMER_KYC_SDK_FLOW_REQUIRED | SDK links generated | User needs to complete identity verification |
CUSTOMER_KYC_SDK_FLOW_COMPLETED | User finishes SDK | Identity verification submitted |
CUSTOMER_KYC_FINISHED | Final outcome reached | KYC approved or denied (check status field) |
CUSTOMER_KYC_RESTARTED | POST /v1/compliance/kyc/:id/rerun | KYC re-run, new onboarding created |
CUSTOMER_KYC_SDK_EXPIRED | SDK links expire | Links expired before user completed |
CUSTOMER_KYC_ERROR | Verification error | System error during verification |
Webhook Payload
{
"eventType": "CUSTOMER_KYC_SDK_FLOW_COMPLETED",
"data": {
"customerId": "uuid",
"status": "APPROVED",
"onboardingId": "uuid"
}
}
For CUSTOMER_KYC_RESTARTED, also includes previousOnboardingId.
Compliance Status API
Endpoint: GET /v1/compliance/status/:customerId
Returns actionable compliance data without requiring message parsing.
Response Structure
{
"isCompliant": false,
"onboardingStatus": "PROCESSING",
"nextAction": "UPLOAD_DOCUMENT",
"checks": [
{
"type": "KYC_STATUS",
"passed": false,
"required": true,
"suggestedAction": "UPLOAD_DOCUMENT"
},
{
"type": "DOC_SOURCE_OF_FUNDS",
"passed": false,
"required": true,
"suggestedAction": "UPLOAD_DOCUMENT"
},
...
],
"summary": {
"passed": 8,
"failed": 2,
"requiredFailed": ["KYC_STATUS", "DOC_SOURCE_OF_FUNDS"]
}
}
Suggested Action Values
| Action | What to do |
|---|---|
START_KYC | Initiate KYC |
COMPLETE_SDK_FLOW | User must complete identity verification SDK |
UPLOAD_DOCUMENT | Upload required document via API |
UPDATE_PROFILE | Update customer profile via PATCH /v1/customers/:id — check which profile checks failed to determine what to update |
RERUN_KYC | Rerun KYC |
WAIT | No user action needed - system processing (e.g., SDK done, docs uploaded, awaiting approval) |
CONTACT_SUPPORT | Terminal failure, verification error, or denied - requires support |
Check Types
| Check | Description | Required |
|---|---|---|
KYC_DATA_PRESENT | Customer has KYC data submitted | Always |
KYC_STARTED | KYC process initiated | Always |
SDK_VERIFICATION_COMPLETED | Identity verification SDK completed | CF_KYC only* |
KYC_STATUS | Overall KYC approved/denied | Always |
REGISTRATION_ADDRESS | Registration address on file | Always |
TAX_COUNTRY | Tax country specified | Always |
OCCUPATION | Occupation registered | Always |
DOC_SOURCE_OF_FUNDS | Source of funds document | Always |
DOC_FATCA | W9/W8BEN document | Always |
DOC_BIOMETRIC_REPORT | Biometric verification report | External KYC only* |
DOC_PROOF_OF_ADDRESS | Proof of address document | Only when no IP address |
*See External KYC Integration for details on strategy-dependent checks.
Handling UPDATE_PROFILE
When nextAction is UPDATE_PROFILE, one or more profile data checks have failed. The checks array tells you exactly which fields are missing:
| Failed Check | What to update via PATCH /v1/customers/:id |
|---|---|
KYC_DATA_PRESENT | Submit KYC data — provide the kyc object (name, birth date, document number, address, etc.) |
REGISTRATION_ADDRESS | Provide kyc.mainAddress with the customer's registration address |
TAX_COUNTRY | Provide kyc.nationality with the customer's country code |
OCCUPATION | Provide kyc.occupation with the customer's occupation code |
To determine what needs updating:
- Call
GET /v1/compliance/status/:customerId - Find all checks where
passed: falseandsuggestedAction: "UPDATE_PROFILE" - Use
GET /v1/customers/:idto see the customer's current profile data - Call
PATCH /v1/customers/:idwith the missing fields
// Example: compliance status shows OCCUPATION and REGISTRATION_ADDRESS failed
{
"checks": [
{
"type": "REGISTRATION_ADDRESS",
"passed": false,
"required": true,
"suggestedAction": "UPDATE_PROFILE"
},
{
"type": "OCCUPATION",
"passed": false,
"required": true,
"suggestedAction": "UPDATE_PROFILE"
}
]
}
// Fix: PATCH /v1/customers/:id
{
"kyc": {
"mainAddress": {
"street1": "123 Main St",
"cityCounty": "New York",
"stateRegion": "NY",
"zip": "10001",
"countryCode": "US"
},
"occupation": "11"
}
}
Complete Integration Flow (Standard)
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 1a: Customer Creation (without KYC data) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │──POST /v1/customers──────────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │◀────────────────────────────────────────────CUSTOMER_CREATED─│ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ KYC_DATA_PRESENT: false │ │ │
│ │ nextAction: UPDATE_PROFILE │ │ │
│ │ │ │ │
│ │──PATCH /v1/customers/:id─────▶│ (add KYC data) │ │
│ │◀────────────────────────────────────────────CUSTOMER_UPDATED─│ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 1b: Customer Creation (with KYC data) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │──POST /v1/customers──────────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │◀────────────────────────────────────────────CUSTOMER_CREATED─│ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ KYC_DATA_PRESENT: true │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────────────────┐
│ PHASE 2: KYC Initiation │
├────────────────────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ KYC_DATA_PRESENT: true │ │ │
│ │ KYC_STARTED: false │ │ │
│ │ nextAction: START_KYC │ │ │
│ │ │ │ │
│ │──POST /v1/compliance/kyc─────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ { sdk: { link, qrCode } } │ │ │
│ │◀───────────────────────────────────────────────────────CUSTOMER_KYC_STARTED─│ │
│ │◀─────────────────────────────────────────────CUSTOMER_KYC_SDK_FLOW_REQUIRED─│ │
│ │ │ │ │
│ │ Display SDK link/QR to user │ │ │
│ │
└───────────────────────────────────────────────── ───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 3: User Completes SDK │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │ (User completes SDK flow) │ │ │
│ │ │ │ │
│ │◀──────────────────────────────────CUSTOMER_KYC_SDK_FLOW_DONE─│ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀───────────────────────────── │ │ │
│ │ SDK_VERIFICATION_COMPLETED: ✓│ │ │
│ │ KYC_STATUS: false │ │ │
│ │ DOC_SOURCE_OF_FUNDS: false │ │ │
│ │ DOC_FATCA: false │ │ │
│ │ nextAction: UPLOAD_DOCUMENT │ │ │
│ │
└────────────────────── ───────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 4: Document Upload │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │──POST /compliance/upload-doc─▶│ (Source of Funds) │ │
│ │◀──────────────────────────────│ │ │
│ │ │ │ │
│ │──POST /compliance/upload-doc─▶│ (W9 or W8BEN) │ │
│ │◀──────────────────────────────│ │ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ All DOC_* checks: ✓ │ │ │
│ │ KYC_STATUS: false │ │ │
│ │ nextAction: WAIT │ (processing, docs present) │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 5: KYC Approved │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │◀─────────────────────────────────CUSTOMER_KYC_FINISHED───────│ │
│ │ │ (status: APPROVED) │ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ isCompliant: true │ │ │
│ │ nextAction: null │ │ │
│ │ │ │ │
│ │ Customer ready for │ │ │
│ │ virtual account creation │ │ │
│ │
└──────────────────────────────── ─────────────────────────────────────────────┘
External KYC Integration
For clients who perform identity verification through their own KYC provider, Connect Financial offers an External KYC integration path. This allows you to leverage your existing KYC infrastructure while still meeting Connect Financial's compliance requirements.
How External KYC Differs
| Aspect | Standard (CF_KYC) | External KYC |
|---|---|---|
| Identity Verification | Connect Financial SDK | Your KYC provider |
| SDK Links | Provided | Not provided |
| Approval Trigger | SDK completion + documents | Documents only |
Key Differences
-
When you call
POST /v1/compliance/kyc, the response contains onlyonboardingdata—nosdklinks or QR codes. -
The
SDK_VERIFICATION_COMPLETEDcheck returnspassed: trueandrequired: falsesince your external provider handles verification. -
You must upload a
BIOMETRIC_REPORTdocument from your KYC provider. This replaces the biometric data that would normally come from our SDK. -
Once all required documents are uploaded and occupation is set, the customer is automatically approved—no waiting for SDK completion.
External KYC Integration Flow
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 1: Customer Creation (with KYC data) │
├─────────── ──────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │──POST /v1/customers──────────▶│ (include kycData) │ │
│ │◀──────────────────────────────│ │ │
│ │◀────────────────────────────────────────────CUSTOMER_CREATED─│ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ KYC_DATA_PRESENT: true │ │ │
│ │ nextAction: START_KYC │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 2: KYC Initiation (No SDK) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │──POST /v1/compliance/kyc─────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ { onboarding: {...} } │ ← No SDK links! │ │
│ │◀───────────────────────────────────────────CUSTOMER_KYC_STARTED─│ │
│ │ │ │ │
│ │ (No CUSTOMER_KYC_SDK_FLOW_REQUIRED webhook) │ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ SDK_VERIFICATION_COMPLETED: │ │ │
│ │ passed: true │ ← Auto-passes for │ │
│ │ required: false │ External KYC │ │
│ │ DOC_BIOMETRIC_REPORT: │ │ │
│ │ passed: false │ │ │
│ │ required: true │ ← Required for External KYC │ │
│ │ nextAction: UPLOAD_DOCUMENT │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 3: Document Upload (including Biometric Report) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │ (Run your external KYC verification) │ │
│ │ │ │ │
│ │──POST /compliance/upload-doc─▶│ (Biometric Report from │ │
│ │◀─────── ───────────────────────│ your KYC provider) │ │
│ │ │ │ │
│ │──POST /compliance/upload-doc─▶│ (Source of Funds) │ │
│ │◀──────────────────────────────│ │ │
│ │ │ │ │
│ │──POST /compliance/upload-doc─▶│ (W9 or W8BEN) │ │
│ │◀──────────────────────────────│ │ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ All DOC_* checks: ✓ │ │ │
│ │ KYC_STATUS: false │ │ │
│ │ nextAction: WAIT │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ PHASE 4: Automatic Approval │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Client API Webhook │
│ │ │ │ │
│ │ (System auto-approves when │ │ │
│ │ all docs present + occupation set) │ │
│ │ │ │ │
│ │◀──────────────────────────────────────CUSTOMER_KYC_FINISHED──│ │
│ │ │ (status: APPROVED) │ │
│ │ │ │ │
│ │──GET /compliance/status──────▶│ │ │
│ │◀──────────────────────────────│ │ │
│ │ isCompliant: true │ │ │
│ │ onboardingStatus: APPROVED │ │ │
│ │ nextAction: null │ │ │
│ │ │ │ │
│ │ Customer ready for │ │ │
│ │ virtual account creation │ │ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Required Documents for External KYC
| Document | Type Code | Description |
|---|---|---|
| Biometric Report | BIOMETRIC_REPORT | Verification report from your KYC provider (PDF) |
| Source of Funds | SOURCE_OF_FUNDS | Document proving source of funds |
| Tax Document | W9 or W8BEN | W9 for US persons, W8BEN for non-US |
| Proof of Address | PROOF_OF_ADDRESS | Only if customer has no IP address on file |
Example: Compliance Status Response (External KYC)
{
"isCompliant": false,
"onboardingStatus": "PROCESSING",
"nextAction": "UPLOAD_DOCUMENT",
"checks": [
{
"type": "KYC_DATA_PRESENT",
"passed": true,
"required": true
},
{
"type": "KYC_STARTED",
"passed": true,
"required": true
},
{
"type": "SDK_VERIFICATION_COMPLETED",
"passed": true,
"required": false
},
{
"type": "KYC_STATUS",
"passed": false,
"required": true,
"suggestedAction": "UPLOAD_DOCUMENT"
},
{
"type": "DOC_BIOMETRIC_REPORT",
"passed": false,
"required": true,
"suggestedAction": "UPLOAD_DOCUMENT"
},
{
"type": "DOC_SOURCE_OF_FUNDS",
"passed": false,
"required": true,
"suggestedAction": "UPLOAD_DOCUMENT"
},
{
"type": "DOC_FATCA",
"passed": false,
"required": true,
"suggestedAction": "UPLOAD_DOCUMENT"
}
],
"summary": {
"passed": 6,
"failed": 4,
"requiredFailed": ["KYC_STATUS", "DOC_BIOMETRIC_REPORT", "DOC_SOURCE_OF_FUNDS", "DOC_FATCA"]
}
}
Webhook Events for External KYC
External KYC uses a subset of the standard webhook events:
| Event | Fired? | Notes |
|---|---|---|
CUSTOMER_KYC_STARTED | ✓ | When POST /v1/compliance/kyc is called |
CUSTOMER_KYC_SDK_FLOW_REQUIRED | ✗ | Never fired—no SDK required |
CUSTOMER_KYC_SDK_FLOW_COMPLETED | ✗ | Never fired—no SDK required |
CUSTOMER_KYC_FINISHED | ✓ | When all requirements met and approved |
Getting External KYC Access
Contact your Connect Financial account representative to configure your integration for External KYC.
Edge Case Flows
SDK Expired
Webhook: CUSTOMER_KYC_SDK_EXPIRED
│
▼
GET /compliance/status
│
├─ SDK_VERIFICATION_COMPLETED: false
└─ nextAction: RERUN_KYC
│
▼
POST /compliance/kyc/:onboardingId/rerun
│
▼
Webhook: CUSTOMER_KYC_RESTARTED
│
▼
(Flow continues from Phase 2)
KYC Denied
Webhook: CUSTOMER_KYC_FINISHED (status: DENIED_COMPLIANCE)
│
▼
GET /compliance/status
│
├─ onboardingStatus: DENIED_COMPLIANCE
├─ KYC_STATUS: false
└─ nextAction: CONTACT_SUPPORT
│
▼
Contact Connect Financial support
Verification Error
Webhook: CUSTOMER_KYC_ERROR
│
▼
GET /compliance/status
│
├─ SDK_VERIFICATION_COMPLETED: false
└─ nextAction: CONTACT_SUPPORT
│
▼
Contact Connect Financial support
Under Review
When identity verification requires manual review by our compliance team, the system enters a "pending review" state.
Webhook: CUSTOMER_KYC_SDK_FLOW_COMPLETED
│
▼
GET /compliance/status
│
├─ SDK_VERIFICATION_COMPLETED: false (pending review, not yet completed)
├─ KYC_STATUS: false (awaiting decision)
└─ nextAction: WAIT
│
▼
Wait for review completion:
- Poll /compliance/status periodically
- Or await CUSTOMER_KYC_FINISHED webhook
│
▼
Review outcome:
- APPROVED → CUSTOMER_KYC_FINISHED (status: APPROVED)
- DENIED → CUSTOMER_KYC_FINISHED (status: DENIED_COMPLIANCE)
Important: During manual review, SDK_VERIFICATION_COMPLETED remains false because the verification is not yet complete as it's awaiting human decision. The nextAction: WAIT indicates no user action is required.