Skip to main content
Know Your Customer (KYC) verification is required before a user can receive payments through Cadana. You submit identity documents and personal information via the API, and Cadana handles automated verification. This page covers the submission requirements, status tracking, and webhook events.

KYC Flow

StatusMeaningUser can transact?
not startedKYC has not been submittedNo
processingDocuments submitted, verification in progressNo
approvedVerification successfulYes
rejectedVerification failed — resubmission neededNo
Most verifications complete automatically within minutes. If automated checks can’t verify the user’s identity, a manual review may take 1-2 business days.

Submit KYC

Submit identity information and documents for a user. Upload document images first using the file upload flow, then pass the returned fileId values. Returns 204 on success. The user’s KYC status moves to processing.

Personal Information

FieldAPI FieldRequiredRules
First namefirstNameYesMust match government-issued ID exactly
Last namelastNameYesMust match government-issued ID exactly
Date of birthdobYesFormat: YYYY-MM-DD
NationalitynationalityYes2-letter ISO country code (e.g., US, NG, KE)

Identity Document

FieldAPI FieldRequiredRules
Document typeidDetails.typeYesSee supported types below
Document numberidDetails.numberYesUnique identifier on the document
Issuing authorityidDetails.issuedByYesAuthority that issued the document
Issue dateidDetails.issuedDateYesFormat: YYYY-MM-DD
Expiration dateidDetails.expirationDateYesFormat: YYYY-MM-DD. Must not be expired
Issuing countryidDetails.issuedCountryCodeYes2-letter ISO country code
Front of IDidDetails.frontFileIdYesfileId from file upload
Back of IDidDetails.backFileIdNoRequired for driver’s licenses and some national IDs
SelfieidDetails.selfieFileIdYesPhoto of user holding the document
Supported document types:
DocumentAPI Value
Passportpassport
Driver’s licensedriver_license
National ID cardnational_id
ID cardid_card
Voter ID cardvoter_id_card
Images must be clear and readable with all text visible. Supported formats: JPEG, PNG.

Address (Optional)

If provided, all required address fields must be completed.
FieldAPI FieldRequired
Street addressaddress.line1Yes
Address line 2address.line2No
Cityaddress.cityYes
State / Provinceaddress.stateYes
Postal codeaddress.postalCodeYes
Countryaddress.countryCodeYes (2-letter ISO code)
An address proof document can be provided via addressProofFileId (utility bill, bank statement, or government document dated within the last 3 months).

Check KYC Status

Retrieve a user’s current KYC status. Response:
{
  "userKyc": {
    "firstName": "John",
    "lastName": "Doe",
    "identity": "approved",
    "address": "not started",
    "idDetails": {
      "country": "US",
      "type": "Drivers license"
    }
  }
}
Identity and address verification are tracked separately. A user needs at minimum identity: "approved" to receive payments. If a verification is rejected, the identityStatusReason or addressStatusReason field explains why.

Resubmit KYC

If a user’s identity or address verification is rejected, use the PATCH endpoint to resubmit corrected information. You can resubmit identity, address, or both in a single request. Resubmission rules:
SectionCan resubmit when
IdentityStatus is rejected
AddressStatus is not started or rejected
At least one of identity or address must be provided. When a section is included, all of its fields are required.

Resubmit identity only

Resubmit address only

Returns 204 on success. Only the resubmitted section(s) move to processing — approved sections remain unchanged.

Webhook Events

user.kyc.updated

Fired on every KYC status change — processing, approved, or rejected. The type field indicates which verification component changed.
{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "eventType": "user.kyc.updated",
  "version": "1.0",
  "timestamp": 1765359752,
  "data": {
    "userId": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e",
    "status": "approved",
    "type": "identity",
    "tenantKey": "cad95193904"
  }
}
FieldDescription
userIdThe user whose KYC status changed
statusNew status: processing, approved, or rejected
typeVerification component: identity or address
For rejected verifications, fetch the user’s KYC details with GET /v1/users/{userId}/kyc to see the failure reason.

user.kyc.expiry

Fired when a user’s identity document is approaching expiry or has expired.
{
  "id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
  "eventType": "user.kyc.expiry",
  "version": "1.0",
  "timestamp": 1765359752,
  "data": {
    "userId": "8ef9a712-cdae-4110-b1ea-9ba95abbee6e",
    "stage": "about-to-expire",
    "documentType": "passport",
    "expiryDate": "2026-03-15",
    "tenantKey": "cad95193904"
  }
}
StageMeaning
about-to-expireDocument expires within 30 days
in-grace-periodExpired but within 60-day grace period — existing transactions continue, new ones may be restricted
expiredPast grace period — user must re-verify
See Events for all event types and payload details.

Handling Rejections

When KYC is rejected, the user needs to resubmit. Common rejection reasons:
ReasonUser action
Document expiredSubmit valid, non-expired document
Image unreadableRetake photo with good lighting
Document damagedSubmit undamaged document
Info mismatchVerify name and DOB match the document exactly
Unsupported documentSubmit an accepted document type
To resubmit, call PATCH /v1/users/{userId}/kyc with corrected information for the rejected section(s). The status resets to processing.

Sandbox Testing

Use sentinel values to simulate KYC approval or rejection in the sandbox environment without waiting for real verification. These sentinels work with both initial submission (POST) and resubmission (PATCH).

Identity Verification

Set idDetails.number to a sentinel value:
Test ValueFieldResult
auto-approveidDetails.numberIdentity automatically approved
auto-rejectidDetails.numberIdentity automatically rejected

Address Verification

Set address.line2 to a sentinel value:
Test ValueFieldResult
auto-approveaddress.line2Address automatically approved
auto-rejectaddress.line2Address automatically rejected
You can combine both sentinels in a single request to auto-resolve identity and address independently. For example, idDetails.number: "auto-approve" with address.line2: "auto-reject" will approve identity and reject address.

Testing the Resubmission Flow

To test the full rejection-to-resubmission cycle in sandbox:
  1. Submit KYC with idDetails.number: "auto-reject" to get a rejected identity
  2. Resubmit via PATCH with idDetails.number: "auto-approve" to approve it
These test values only work in the sandbox environment and are silently ignored in production. Sentinel values are case-insensitive.
See Sandbox & Testing for all test values.

Next Steps

Working with Files

Upload identity documents before submitting KYC

KYB Requirements

Business verification requirements

Onboard Workers

Create Person and User records

Sandbox & Testing

Test values and simulated scenarios