Onboard a New Cardholder

This guide walks through the complete cardholder onboarding journey — from initial creation through compliance approval — with annotated field-level notes, a full decision tree for every status outcome, and guidance on the two available KYC paths (Didit and SumSub).

Overview

flowchart TD
    A["1. Create cardholder\nPOST /cardholders"] --> B["status = 4 (Draft)"]
    B --> C{"Edits needed?"}
    C -- "Yes" --> D["Edit cardholder\nPUT /cardholders/{id}\n(only callable in status 2/4/6/7)"]
    D --> B
    C -- "No" --> E["2. Submit to compliance\nPUT /cardholders/{id}/kyc-submit"]
    E -->|"Processing error during submit"| F6["status = 6 (Error)"]
    F6 -.->|"may be possible\n(not guaranteed)"| D
    E --> F3["status = 3 (Under Review)\napplicationLink returned"]
    F3 --> G["3. Share applicationLink\nwith cardholder"]
    G --> H["Cardholder completes KYC\n(photo ID + proof of address + liveness)"]
    H --> I{"4. Poll status\nGET /cardholders/{id}"}
    I -- "status = 1" --> J["✅ Approved — ready to issue cards"]
    I -- "status = 5 (Pending)\ntransitional" --> I
    I -- "status = 3\nstill in progress" --> I
    I -- "status = 3 + link expired" --> M["Regenerate KYC URL\nPOST .../kyc-url/refresh"]
    M --> G
    I -- "status = 2\nCompliance Decline" --> ND["Notify cardholder\nSee: Handling declines"]
    I -- "status = 7\nAdmin Decline" --> ND
    ND --> ST["Raise support ticket"]
    ND -.->|"may be possible\n(not guaranteed)"| D

    style F6 fill:#fff3cd,stroke:#856404
    style ND fill:#f8d7da,stroke:#721c24
    style J fill:#d4edda,stroke:#155724
📘

Dashed lines in the diagram represent probabilistic, not deterministic, paths — after statuses 6 (Error), 2 (Compliance Decline), or 7 (Admin Decline), editing and re-submitting may or may not be possible depending on the specific reason for the outcome. When in doubt, raise a support ticket first. See Handling declines below.


Step 1: Create the cardholder

POST /cardholders

Required fields

FieldTypeConstraintsNotes
firstNamestring2–50 charsLegal name as it appears on government-issued ID
lastNamestring2–50 charsLegal name as it appears on government-issued ID
genderinteger enum0 Male · 1 Female · 2 Other
nationalitystring2–50 charsAs it appears on government-issued ID
placeOfBirthstringexactly 3 charsISO 3166-1 Alpha-3 country code (e.g. USA, GBR, ARE)
dobstringYYYY-MM-DD, exactly 10 charsLegal date of birth as on government-issued ID
adrLine1string4–50 charsAs it appears on proof of address
citystring2–50 charsAs it appears on proof of address
statestring2–50 charsUS residents: 2-letter USPS abbreviation. Non-US where not applicable: XX
countrystringexactly 2 chars, uppercaseISO 3166-1 Alpha-2 (e.g. US, GB, AE)
zipCodestring5–12 charsUS residents: 5-digit ZIP. Non-US where not applicable: 00000
emailAdrstring6–50 chars
callingCodestring1–3 digitsITU dialing code — zero-padded to 3 digits (e.g. 001, 044, 971)
cellNumstring10–20 digitsMobile number; dialing code passed separately via callingCode
countryCallingCodestringexactly 2 chars, uppercaseISO 3166-1 Alpha-2 country code associated with phoneNum
phoneNumstring10–20 digitsLandline / alternate number

Optional fields

FieldTypeNotes
midNamestringmax 50 chars
adrLine2stringmax 50 chars
cardHolderFirstNamestringmax 50 chars — preferred name to print on cards. Defaults to firstName
cardHolderLastNamestringmax 50 chars — preferred name to print on cards. Defaults to lastName
employeeIDstringOptional corporate identifier (e.g. cost-centre code)
transactionLimitintegerDecimal-implied; capped by Program ceiling; inherited by all cards if set
sumsubEnabledinteger enum0 (default, Didit) · 1 (SumSub) — see KYC paths

Field gotchas

🚧

Four fields with inconsistent country/code conventions — get these right before submitting:

FieldExpectsExample
placeOfBirthISO 3166-1 Alpha-3 (3-letter)USA, GBR, ARE
countryISO 3166-1 Alpha-2 (2-letter)US, GB, AE
countryCallingCodeISO 3166-1 Alpha-2 (2-letter) — not a dialing code despite the nameUS, GB, AE
callingCodeITU dialing code, zero-padded to 3 digits001 (US), 044 (UK), 971 (UAE)

Example request

{
  "firstName": "Jordan",
  "lastName": "Reyes",
  "gender": 0,
  "nationality": "American",
  "placeOfBirth": "USA",
  "dob": "1990-05-14",
  "adrLine1": "123 Market Street",
  "city": "San Francisco",
  "state": "CA",
  "country": "US",
  "zipCode": "94105",
  "emailAdr": "[email protected]",
  "callingCode": "001",
  "cellNum": "4155551234",
  "countryCallingCode": "US",
  "phoneNum": "4155551234",
  "cardHolderFirstName": "Jordan",
  "cardHolderLastName": "Reyes"
}

Response: { "status": "success", "cardholderId": 10532 }

Save cardholderId — it is the key for every subsequent operation on this cardholder.


Step 2: Edit the cardholder (optional, while in Draft)

If you need to correct any fields before submitting for compliance review, use:

PUT /cardholders/{cardholderId}
❗️

This is a full replacement, not a partial update. All fields are required — omitting a field may result in a validation error or a blank value. Always retrieve the current record first (GET /cardholders/{cardholderId}) and submit the complete body with your corrections applied.

🚧

Status restriction: PUT /cardholders/{cardholderId} is only callable when status is 2 (Compliance Decline), 4 (Draft), 6 (Error), or 7 (Admin Decline) — and even then, only where re-submission is possible (see Handling declines). It cannot be called while status = 3 (Under Review) or status = 1 (Approved).

For lightweight updates to transactionLimit and contact details that can be made at any time regardless of status, use PUT /cardholders/{cardholderId}/update instead.

To changeUseStatus restriction
Any compliance-locked field (name, dob, address, nationality, etc.)PUT /cardholders/{cardholderId}Only in status 2/4/6/7 — and only where re-submission is possible
transactionLimit or contact detailsPUT /cardholders/{cardholderId}/updateAny time
Compliance-locked field on an Approved (1) or Under Review (3) cardholderNot possible via APIRaise a support ticket — see Changing locked fields on an approved cardholder

Step 3: Submit to compliance

PUT /cardholders/{cardholderId}/kyc-submit

No request body is required. On success, the cardholder moves to status = 3 (Under Review) and the response includes an applicationLink:

{
  "status": "success",
  "applicationLink": "https://kyc.didit.me/session/abc123..."
}

If a processing error occurs during the submission itself, the cardholder will enter status = 6 (Error) rather than status = 3. This is distinct from a Compliance Decline — see Handling declines.

🚧

Once submitted, compliance-locked fields cannot be changed via PUT /cardholders/{id}. If the cardholder was submitted with an error in a locked field (name, dob, address, etc.), a new Cardholder record will typically need to be created. Compliance-locked fields are:

firstName, midName, lastName, gender, nationality, placeOfBirth, dob, adrLine1, city, state, country, zipCode, sumsubEnabled

See Cardholders & the Compliance Lifecycle for the full table.


Step 4: Share the KYC URL with the cardholder

Deliver the applicationLink to the cardholder through your application — display it as a button or link directing them to complete their identity verification:

  • Government-issued photo ID (passport, national ID card, or driving licence)
  • Proof of address (utility bill, bank statement, or equivalent, matching the registered address)
  • Biometric liveness verification (selfie/video-based, compared against the photo ID)

You can retrieve the existing KYC URL at any time without regenerating it:

GET /cardholders/{cardholderId}/ekyc-url

Returns { "url": "https://..." }.


Step 5: Poll for the compliance outcome

Poll GET /cardholders/{cardholderId} until status moves from 3 (Under Review):

Recommended polling interval

Elapsed timeInterval
0–10 minutes after URL deliveryEvery 30–60 seconds
10 minutes – 2 hoursEvery 5 minutes
2–48 hoursEvery 30 minutes
Beyond 48 hours still Under ReviewRaise a support ticket

Most automated KYC checks complete within minutes; some cases require manual review and may take longer.

Status outcomes

statusOutcomeWhat to do
1✅ Approved — KYC passedProceed to Issue a Virtual Card or Issue & Activate a Physical Card
5Pending — transitional stateContinue polling
3Still Under ReviewContinue polling; regenerate KYC URL if link has expired
2Compliance DeclineSee Handling declines
7Admin DeclineSee Handling declines

KYC URL expiry

If the applicationLink has expired while the cardholder is still status = 3 (Under Review), regenerate it:

POST /cardholders/{cardholderId}/kyc-url/refresh

Returns a new applicationLink. This endpoint is only callable when status = 3.


Handling declines

Status 6 — Error (during submission)

An error during the kyc-submit call itself (not during the KYC review) results in status = 6. Depending on the nature of the error, it may be possible to correct the cardholder record and re-submit — but this is not guaranteed. If the error persists, raise a support ticket.

Status 2 — Compliance Decline

Common reasons for a Compliance Decline include:

  • Biometric mismatch — the liveness check selfie doesn't sufficiently match the photo on the submitted ID document
  • Address / IP location discrepancy — the proof of address doesn't match the IP location recorded during the Didit compliance session (Didit logs the session IP)
  • Automated compliance flag — a risk or sanctions screening rule was triggered; in many cases a manual compliance review can assess and overturn this

For status = 2, it may be possible to regenerate the KYC URL (via support ticket or by re-submitting), correct the issue, and re-attempt. However:

  • If the decline is due to a locked field mismatch (e.g. the address on the cardholder record doesn't match the submitted proof of address), edit-and-resubmit is not possible — the locked field cannot be changed. A new Cardholder record will be required.
  • If the decline is due to an automated flag that requires manual review, raise a support ticket.

Status 7 — Admin Decline

An Admin Decline is a manual, platform-side decision. It is not programmatically recoverable — raise a support ticket for review of the specific case.

The support ticket path

For all decline scenarios where the API alone cannot resolve the issue — including Admin Declines, persistent Compliance Declines requiring manual review, and Error states that don't resolve on re-submission — raise a support ticket:

POST /support/tickets
{
  "programId": 42,
  "cardholderId": 10532,
  "subject": "Compliance Decline — manual review requested",
  "message": "Cardholder 10532 received status 2 (Compliance Decline) after two re-submission attempts. Requesting manual compliance review. No locked field errors believed to be present.",
  "priority": 3
}

See Support Tickets for the full ticket guide.


Changing locked fields on an Approved or Under Review cardholder

If a cardholder's compliance-locked fields (name, date of birth, address, etc.) need to be changed after the cardholder has reached status = 3 (Under Review) or status = 1 (Approved), this cannot be done via the API. Raise a support ticket with:

  • The cardholderId
  • The specific fields that need to change and the corrected values
  • Context / evidence (e.g. cardholder's updated proof of address)

KYC paths

Didit (default)

The standard flow described above. The applicationLink is hosted by Didit. No additional integration is required beyond delivering the link to the cardholder.

SumSub

If the Program has SumSub enabled (sumsubEnabled = 1), the compliance flow uses SumSub's token-based SDK rather than the Didit-hosted URL. The kyc-submit endpoint still triggers the state transition, but the verification experience is delivered via the SumSub SDK embedded in your application.

📘

The SumSub token-exchange process sits alongside the Didit flow described above. If your Program uses SumSub, confirm the integration details with your Axys account team.


Corporate clients

If onboarding a business rather than a consumer, the Cardholder is the natural person responsible and liable for the cards — typically a director, partner, shareholder, or sole trader. The corporate entity is never a Cardholder. See Program Architecture: Corporate use cases.

The optional employeeID field can carry a corporate identifier (employee number, cost-centre code, etc.) for reconciliation purposes.


What's next