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), or7(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
| Field | Type | Constraints | Notes |
|---|---|---|---|
firstName | string | 2–50 chars | Legal name as it appears on government-issued ID |
lastName | string | 2–50 chars | Legal name as it appears on government-issued ID |
gender | integer enum | 0 Male · 1 Female · 2 Other | |
nationality | string | 2–50 chars | As it appears on government-issued ID |
placeOfBirth | string | exactly 3 chars | ISO 3166-1 Alpha-3 country code (e.g. USA, GBR, ARE) |
dob | string | YYYY-MM-DD, exactly 10 chars | Legal date of birth as on government-issued ID |
adrLine1 | string | 4–50 chars | As it appears on proof of address |
city | string | 2–50 chars | As it appears on proof of address |
state | string | 2–50 chars | US residents: 2-letter USPS abbreviation. Non-US where not applicable: XX |
country | string | exactly 2 chars, uppercase | ISO 3166-1 Alpha-2 (e.g. US, GB, AE) |
zipCode | string | 5–12 chars | US residents: 5-digit ZIP. Non-US where not applicable: 00000 |
emailAdr | string | 6–50 chars | |
callingCode | string | 1–3 digits | ITU dialing code — zero-padded to 3 digits (e.g. 001, 044, 971) |
cellNum | string | 10–20 digits | Mobile number; dialing code passed separately via callingCode |
countryCallingCode | string | exactly 2 chars, uppercase | ISO 3166-1 Alpha-2 country code associated with phoneNum |
phoneNum | string | 10–20 digits | Landline / alternate number |
Optional fields
| Field | Type | Notes |
|---|---|---|
midName | string | max 50 chars |
adrLine2 | string | max 50 chars |
cardHolderFirstName | string | max 50 chars — preferred name to print on cards. Defaults to firstName |
cardHolderLastName | string | max 50 chars — preferred name to print on cards. Defaults to lastName |
employeeID | string | Optional corporate identifier (e.g. cost-centre code) |
transactionLimit | integer | Decimal-implied; capped by Program ceiling; inherited by all cards if set |
sumsubEnabled | integer enum | 0 (default, Didit) · 1 (SumSub) — see KYC paths |
Field gotchas
Four fields with inconsistent country/code conventions — get these right before submitting:
Field Expects Example placeOfBirthISO 3166-1 Alpha-3 (3-letter) USA,GBR,AREcountryISO 3166-1 Alpha-2 (2-letter) US,GB,AEcountryCallingCodeISO 3166-1 Alpha-2 (2-letter) — not a dialing code despite the name US,GB,AEcallingCodeITU dialing code, zero-padded to 3 digits 001(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 whenstatusis2(Compliance Decline),4(Draft),6(Error), or7(Admin Decline) — and even then, only where re-submission is possible (see Handling declines). It cannot be called whilestatus = 3(Under Review) orstatus = 1(Approved).For lightweight updates to
transactionLimitand contact details that can be made at any time regardless of status, usePUT /cardholders/{cardholderId}/updateinstead.
| To change | Use | Status 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 details | PUT /cardholders/{cardholderId}/update | Any time |
Compliance-locked field on an Approved (1) or Under Review (3) cardholder | Not possible via API | Raise 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,sumsubEnabledSee 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 time | Interval |
|---|---|
| 0–10 minutes after URL delivery | Every 30–60 seconds |
| 10 minutes – 2 hours | Every 5 minutes |
| 2–48 hours | Every 30 minutes |
| Beyond 48 hours still Under Review | Raise a support ticket |
Most automated KYC checks complete within minutes; some cases require manual review and may take longer.
Status outcomes
status | Outcome | What to do |
|---|---|---|
1 | ✅ Approved — KYC passed | Proceed to Issue a Virtual Card or Issue & Activate a Physical Card |
5 | Pending — transitional state | Continue polling |
3 | Still Under Review | Continue polling; regenerate KYC URL if link has expired |
2 | Compliance Decline | See Handling declines |
7 | Admin Decline | See 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
- Issue a Virtual Card
- Issue & Activate a Physical Card
- Support Tickets
- Cardholders & the Compliance Lifecycle
- Poll Compliance Status (Recipe — full backoff/retry script)
