Cards

Card Request

Create a new card request and track its latest request status.

Flow Summary

The current card request flow is:

Step 1. Complete KYC and cardholder setup
Use KYC first

Step 2. Create the card request
POST /api/v1/card-request

Step 3. Check the latest request status
GET /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_type is required
  • Current enum values are VIRTUAL and PHYSICAL
  • country_id is required
  • address is required
  • post_code is required
  • post_code must be between 1000 and 9999999999

Important backend behavior

  • agent_id and mobile_user_id are not accepted from the client; the backend fills them from the auth token
  • The service generates a unique merchant_order_sn in the format HTP-<uuid>
  • The initial record is created with:
    • card_status = AWAITING_PAYMENT
    • mgr_status = PENDING
    • admin_status = PENDING
    • request_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

NameRequiredNotes
pageNoDefault 1
limitNoDefault 10
statusNoFilters 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 status filter applies to the raw card_status field, 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.status
    • mobile_user.uid
    • cardholder name
    • country name/code
  • card_limit and limit_per_transaction are formatted as strings in the response

Common failures

  • 404: request not found for this user/agent
  • 401: 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

NameRequiredNotes
card_typeNoIf omitted, the backend defaults to VIRTUAL

Returned summary statuses

  • APPROVED
  • PENDING
  • PROCESSING
  • FAILED
  • NOT_FOUND

Current backend status mapping

  • APPROVED: admin_status = APPROVED and mgr_status = APPROVED and card_status = SUCCESS
  • FAILED: manager declined, admin declined, card_status = FAILED, or payment_status = EXPIRED
  • PROCESSING: physical card only, card_status = PROCESSING, and an activation_code already exists
  • PENDING: 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

  1. Do not treat POST /card-request as the whole card issuance result; it only creates the request and payment order.
  2. Use /card-request/status for the simple app badge/status summary.
  3. Use /card-request/{uuid} when you need the full detail screen for a specific request.
Copyright © 2026