Card Request
Flow Summary
The current card request flow is:
Step 1. Complete KYC and cardholder setup
Use KYC first
Step 2. Create the card requestPOST /api/v1/card-request
Step 3. Check the latest request statusGET /api/v1/card-request/status
All card request routes below should be treated as protected routes and sent with:
Authorization: Bearer <access_token>
The create endpoint also passes through DecryptField(), so it supports either plain JSON or the encrypted wrapper described in Overview.
Important Prerequisite
The backend does not allow a card request unless the current mobile user already has a card_holder record with:
card_status = SUCCESS
In practice, that means the user must already have completed the KYC/cardholder flow successfully before POST /api/v1/card-request can work.
If no successful cardholder exists, the service returns a not-found style error.
1. Create Card Request
POST /api/v1/card-request
This route is protected and also IP-rate-limited to 60 requests per minute.
Request
{
"card_type": "VIRTUAL",
"country_id": 114,
"address": "Phnom Penh",
"post_code": 120101
}
Request rules
card_typeis required- Current enum values are
VIRTUALandPHYSICAL country_idis requiredaddressis requiredpost_codeis requiredpost_codemust be between1000and9999999999
Important backend behavior
agent_idandmobile_user_idare not accepted from the client; the backend fills them from the auth token- The service generates a unique
merchant_order_snin the formatHTP-<uuid> - The initial record is created with:
card_status = AWAITING_PAYMENTmgr_status = PENDINGadmin_status = PENDINGrequest_by = MOBILE
- After the DB row is created, the service makes a synchronous RPC call to create a payment order
- If that payment-order RPC fails, the API returns an error and the card request flow is treated as failed
- A user notification is created in the background after successful creation
Success response
{
"status_code": 201,
"message": "Success",
"data": {
"id": 42,
"uuid": "5e5d4990-2241-46dc-9dbd-8abcf97e6061",
"card_status": "AWAITING_PAYMENT",
"payment_status": "PENDING",
"mgr_status": "PENDING",
"admin_status": "PENDING",
"merchant_order_sn": "HTP-8c2af6ac-7d58-4b1e-8bb7-3ee80f7a9d64",
"card_holder_id": 11,
"country_id": 114,
"address": "Phnom Penh",
"post_code": 120101
}
}
2. List Card Requests
GET /api/v1/card-request
Lists the current user’s card requests with pagination.
Query parameters
| Name | Required | Notes |
|---|---|---|
page | No | Default 1 |
limit | No | Default 10 |
status | No | Filters by card_status |
Success response shape
{
"status_code": 200,
"message": "Success",
"data": [
{
"id": 42,
"card_status": "AWAITING_PAYMENT",
"created_at": "2026-02-28T10:00:00Z",
"card_type": "VIRTUAL",
"payment_status": "PENDING"
}
],
"metadata": {
"current_page": 1,
"limit": 10,
"total": 1
}
}
Notes
- The list is filtered to the authenticated mobile user
- Results are sorted by
created_at DESC - The
statusfilter applies to the rawcard_statusfield, not the computed summary status from/status
3. Get Card Request By UUID
GET /api/v1/card-request/{uuid}
Returns the full request details for one specific card request owned by the current user.
Success response notes
- Includes the raw request fields plus:
card_holder_kyc.statusmobile_user.uid- cardholder name
- country name/code
card_limitandlimit_per_transactionare formatted as strings in the response
Common failures
404: request not found for this user/agent401: auth context missing
4. Get Latest Card Request Status
GET /api/v1/card-request/status
This returns a computed summary status for the current user’s latest card request.
Query parameters
| Name | Required | Notes |
|---|---|---|
card_type | No | If omitted, the backend defaults to VIRTUAL |
Returned summary statuses
APPROVEDPENDINGPROCESSINGFAILEDNOT_FOUND
Current backend status mapping
APPROVED:admin_status = APPROVEDandmgr_status = APPROVEDandcard_status = SUCCESSFAILED: manager declined, admin declined,card_status = FAILED, orpayment_status = EXPIREDPROCESSING: physical card only,card_status = PROCESSING, and anactivation_codealready existsPENDING: default fallback, including:- awaiting approvals
AWAITING_PAYMENT- physical card processing without activation code yet
NOT_FOUND: no card request exists for that user/card type
Special physical-card rule
For card_type=PHYSICAL, if the latest successful physical request already exists but there is also a newer pending/processing physical request, the API prefers that pending/processing request when building the status response.
Success response shape
{
"status_code": 200,
"message": "Success",
"data": {
"status": "PENDING",
"card_request": {
"id": 42,
"card_status": "AWAITING_PAYMENT",
"payment_status": "PENDING",
"card_type": "VIRTUAL"
}
}
}
Integration Notes
- Do not treat
POST /card-requestas the whole card issuance result; it only creates the request and payment order. - Use
/card-request/statusfor the simple app badge/status summary. - Use
/card-request/{uuid}when you need the full detail screen for a specific request.