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
All card request routes below should be treated as protected routes and sent with:
Authorization: Bearer <access_token>
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"
}
URL Query Parameters:
method(optional): Payment methodagent-pay: Agent pays on behalf of user using agent's prepaid balanceuser-pay: User pays directly via payment gateway (default)
Request rules
card_typeis required- Current enum values are
VIRTUALandPHYSICAL country_idis requiredaddressis requiredpost_codeis requiredpost_codemust be sent as a stringpost_codemust contain 4 to 10 digitsmethodis optional URL parameter, defaults touser-payif not provided
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_PAYMENTadmin_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
Payment Methods
Agent Payment (agent-pay):
- Payment is automatically deducted from agent's prepaid balance
- Card request is immediately approved
- Card creation starts right away
- No payment order processing required
User Payment (user-pay):
- User must complete payment through payment gateway
- A payment order is created with
merchant_order_sn - Use the payment order endpoint to check payment status:
GET /api/v1/payment-orders/{merchant_order_sn}
- After successful payment, card request is processed based on system settings
Success response
{
"status_code": 201,
"message": "Success",
"data": {
"id": 42,
"uuid": "5e5d4990-2241-46dc-9dbd-8abcf97e6061",
"card_status": "AWAITING_PAYMENT",
"payment_status": "PENDING",
"admin_status": "PENDING",
"merchant_order_sn": "HTP-8c2af6ac-7d58-4b1e-8bb7-3ee80f7a9d64",
"card_type": "VIRTUAL",
"country_id": 114,
"address": "Phnom Penh",
"post_code": 120101
}
}
Response when method=agent-pay (card already approved):
{
"status_code": 201,
"message": "Success",
"data": {
"id": 42,
"uuid": "5e5d4990-2241-46dc-9dbd-8abcf97e6061",
"card_status": "PROCESSING",
"payment_status": "SUCCESS",
"admin_status": "APPROVED",
"merchant_order_sn": "HTP-8c2af6ac-7d58-4b1e-8bb7-3ee80f7a9d64",
"card_type": "VIRTUAL",
"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, including card details if the card has been successfully created.
Response structure
The response has two parts:
- Card Request Details (always returned):
id: Local database IDuuid: Card request UUIDpayment_status: Payment status (PENDING, SUCCESS, EXPIRED, FAILED)card_status: Card request status (AWAITING_PAYMENT, PROCESSING, SUCCESS, FAILED)admin_status: Admin approval statuscard_type: VIRTUAL or PHYSICALmerchant_order_sn: Merchant order serial numbercountry_id,address,post_code: Request details (post_codeis returned as an integer in this API contract)
- Card Details (included only when
card_status = SUCCESS):id: Card local database IDuuid: Card UUIDcard_number: 16-digit card numbercard_id: Card identifier from payment providercard_type: VIRTUAL or PHYSICALcard_provider: MASTER, VISA, etc.first_name,last_name,name_on_card: Cardholder detailscard_limit: Card limit formatted as stringavailable_balance: Current available balancelimit_per_transaction: Per-transaction limitstatus: ACTIVE, BLOCKED, FROZEN, etc.created_at,updated_at: Timestamps
Success response examples
When card is still being processed (card_status ≠ SUCCESS):
{
"status_code": 200,
"message": "Success",
"data": {
"id": 42,
"uuid": "5e5d4990-2241-46dc-9dbd-8abcf97e6061",
"payment_status": "SUCCESS",
"card_status": "PROCESSING",
"admin_status": "APPROVED",
"merchant_order_sn": "HTP-8c2af6ac-7d58-4b1e-8bb7-3ee80f7a9d64",
"card_type": "VIRTUAL",
"country_id": 114,
"address": "Phnom Penh",
"post_code": 120101
}
}
When card has been successfully created (card_status = SUCCESS):
{
"status_code": 200,
"message": "Success",
"data": {
"id": 42,
"uuid": "5e5d4990-2241-46dc-9dbd-8abcf97e6061",
"payment_status": "SUCCESS",
"card_status": "SUCCESS",
"admin_status": "APPROVED",
"merchant_order_sn": "HTP-8c2af6ac-7d58-4b1e-8bb7-3ee80f7a9d64",
"card_type": "VIRTUAL",
"country_id": 114,
"address": "Phnom Penh",
"post_code": 120101,
"card": {
"id": 508,
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"card_number": "4111111111111111",
"card_id": "card_abc123",
"card_type": "VIRTUAL",
"card_provider": "MASTER",
"first_name": "John",
"last_name": "Doe",
"name_on_card": "JOHN DOE",
"card_limit": "5000.00",
"available_balance": "5000.00",
"limit_per_transaction": "1000.00",
"status": "ACTIVE",
"card_currency": "USD",
"created_at": "2026-02-28T10:05:00Z",
"updated_at": "2026-02-28T10:05:00Z"
}
}
}
Important behavior notes
- Card details are conditional: The
cardobject is only included whencard_status = SUCCESS - For PENDING/PROCESSING/FAILED requests: The
cardfield will benullor omitted - Card creation flow:
- Request created →
card_status = AWAITING_PAYMENT - Payment completed →
payment_status = SUCCESS - Approvals granted →
admin_status = APPROVED - Card successfully created →
card_status = SUCCESS(now card details are available)
- Request created →
- Physical cards: May have additional
PROCESSINGstate while activation code is being generated - Idempotency: Calling this endpoint multiple times with the same UUID will return consistent data
Common failures
404: request not found for this user/agent401: auth context missing
Integration Notes
- Do not treat
POST /card-requestas the whole card issuance result; it only creates the request and payment order. - Use
/card-request/{uuid}to get the full detail screen for a specific request. - Poll card creation status:
- For
agent-pay: Card creation starts immediately after request - For
user-pay: Check payment order status first, then poll/card-request/{uuid} - When
card.status = SUCCESS, the response will include full card details - Recommended polling interval: 2-5 seconds
- For
