Platform Card API

A complete REST API integration layer for card issuance, cardholder management, wallet operations, and real-time webhook events.

Overview

The Card API is a RESTful backend that wraps the card platform. As a third-party developer you interact only with this API — you never call Platform directly.

ℹ️
All API endpoints are versioned under /api/v1/. All requests must use POST (or GET where noted). All payloads are JSON.

Base URL

# Live (Production)
https://{api-domain}

# Sandbox
https://{api-domain}/sandbox

Authentication

Every request to /api/v1/* must include your API key in the X-API-KEY request header.

# Example — all requests require this header
X-API-KEY: wc_YourSecretKeyHere
Content-Type: application/json
⚠️
Keep your key secret. Treat it like a password. Do not commit it to source control or expose it in client-side code. If compromised, contact the administrator to revoke and reissue it.

Getting a Key

API keys are issued by the platform administrator via the admin portal. Each key is tied to your developer account. Contact the admin to receive yours.

Missing or Invalid Key

{
  "success": false,
  "code":    401,
  "msg":     "Invalid or missing API key.",
  "data":    null
}

Request Format

All requests use JSON bodies with Content-Type: application/json. Unless otherwise stated, endpoints use the POST method.

cURL Example

curl -X POST https://{api-domain}/sandbox/api/v1/cardholders/occupations \
  -H "X-API-KEY: wc_YourSecretKeyHere" \
  -H "Content-Type: application/json"

Request with Body

curl -X POST https://{api-domain}/sandbox/api/v1/cards/balance \
  -H "X-API-KEY: wc_YourSecretKeyHere" \
  -H "Content-Type: application/json" \
  -d '{
    "cardNo": "4111111111111111"
  }'

Response Format

Every response — success or error — uses the same JSON envelope:

{
  "success": true,      // boolean — true only when code=200
  "code":    200,       // integer status code
  "msg":     "Success",  // human-readable message
  "data":    { ... }    // payload — object, array, or null
}

Always check success === true (or code === 200) before processing data.

Successful List Response Example

{
  "success": true,
  "code":    200,
  "msg":     "Success",
  "data": {
    "total":   42,
    "records": [ ... ]
  }
}

Error Codes

HTTP StatuscodeMeaningAction
200200SuccessProcess data
400400Bad request / business rule errorCheck msg for details
401401Missing or invalid API keyCheck your X-API-KEY header
422422Validation faileddata contains field-level errors
429429Rate limit exceededWait and retry. See Rate Limiting
502502Upstream service errorRetry. If persistent, contact support

Validation Error Example

{
  "success": false,
  "code":    422,
  "msg":     "Validation failed.",
  "data": {
    "email": [ "The email field must be a valid email address." ],
    "cardHolderModel": [ "The selected card holder model is invalid." ]
  }
}

Rate Limiting

Each API key is limited to 60 requests per minute. Exceeding this returns HTTP 429. Implement exponential back-off in your client.

# Retry strategy (example)
attempt 1: immediate
attempt 2: wait 1s
attempt 3: wait 2s
attempt 4: wait 4s

Common — Reference Data

Lookup tables required for other API calls. Cache these responses — they rarely change.

GET /api/v1/common/regions Supported countries/regions
GET /api/v1/common/cities City list with codes
GET /api/v1/common/cities/hierarchical Cities grouped by region
GET /api/v1/common/mobile-codes Supported phone area codes
POST /api/v1/common/files/upload Upload KYC documents (multipart/form-data)
ℹ️
File upload returns a fileId. Pass it as idFrontId, idBackId, or idHoldId when creating a B2C cardholder.

Wallet

On-chain top-up addresses, deposit orders, and wallet transaction history.

POST /api/v1/wallet/v2/coins Supported coins list
POST /api/v1/wallet/v2/create?coinKey=USDT_BEP20&externalUserId=CUSTOMER_001 Return the funding wallet top-up address
POST /api/v1/wallet/card-topup-orders Store a wallet deposit to card top-up mapping
GET /api/v1/wallet/card-topup-orders/{id} Get one card top-up order status
GET /api/v1/wallet/card-topup-orders?txHash=0x... Search card top-up orders
POST /api/v1/wallet/v2/address-list List funding wallet top-up addresses
POST /api/v1/wallet/v2/transactions Transaction history V2
i
Use data.address from /wallet/v2/create as the crypto deposit address. Before or after the user sends funds, create a /wallet/card-topup-orders record with the target cardNo. If available, include txHash; it is the strongest matching field.

Create Top-Up Address

Call POST /api/v1/wallet/v2/create?coinKey=USDT_BEP20. The user should deposit to data.address. Pass externalUserId or userId for tracking, but the returned address is the funding wallet address for the selected network.

{
  "success": true,
  "code": 200,
  "msg": "SUCCESS",
  "data": {
    "coinKey": "USDT_BEP20",
    "externalUserId": "CUSTOMER_001",
    "chain_id": "56",
    "token_id": null,
    "address": "0x..."
  }
}

Create Card Top-Up Order

Create this record so the wallet deposit webhook knows which card to load. The system matches by txHash first, then falls back to API token, amount, source address, coin key, and pending order uniqueness. If the same txHash is submitted again for the same card, the existing order is returned. If the same txHash is submitted for a different card, the API rejects it.

POST /api/v1/wallet/card-topup-orders

{
  "cardNo": "USER_CARD_NO",
  "amount": "100.00",
  "coinKey": "USDT_BEP20",
  "externalUserId": "CUSTOMER_001",
  "sourceAddress": "0xUSER_SENDING_WALLET",
  "txHash": "0xTRANSACTION_HASH"
}

When the wallet deposit is confirmed, the deposit fee is deducted and the net amount is loaded to the card automatically. The net card top-up amount after fees must be at least 1.00 USD; otherwise the order is rejected or marked failed and the funds remain in the wallet balance. The customer does not need to call /cards/deposit for this automated flow.

Check Card Top-Up Order Status

Use GET /api/v1/wallet/card-topup-orders/{id} for one order, or search using id, txHash, cardNo, externalUserId, or status.

GET /api/v1/wallet/card-topup-orders?txHash=0xTRANSACTION_HASH

Status values are pending, deposit_requested, completed, and failed. If status is failed, check errorMessage.

If the chain is not configured yet, the API returns HTTP 503:

{
  "success": false,
  "code": 503,
  "msg": "Deposit address chain mapping is not configured for USDT_BEP20.",
  "data": null
}

POST /api/v1/wallet/v2/address-list returns the funding wallet addresses. Deposit callbacks are handled internally; clients should not call the internal callback endpoint directly.

Cards

Full card lifecycle: create, manage, fund, and query transaction history.

Card Setup
POST /api/v1/cards/support-bins Supported card types and BINs
POST /api/v1/cards/create-v2 Create a virtual card or create/register a physical card (V2)
POST /api/v1/cards/activate-physical Activate a physical card
Card Information
POST /api/v1/cards/info Card details
POST /api/v1/cards/sensitive Encrypted card number, expiry, CVV
POST /api/v1/cards/balance Card balance
POST /api/v1/cards/list List all cards (paginated)
Card Management
POST /api/v1/cards/update Update card label / settings
POST /api/v1/cards/freeze Freeze card
POST /api/v1/cards/unfreeze Unfreeze card
POST /api/v1/cards/cancel Cancel (close) card
POST /api/v1/cards/update-pin Update card PIN
POST /api/v1/cards/note Update card note
Card Funding
POST /api/v1/cards/deposit Deposit funds to card
POST /api/v1/cards/withdraw Withdraw funds from card
Transaction History
POST /api/v1/cards/purchase-transactions Purchase/debit transactions
POST /api/v1/cards/operation-transactions-v2 Operation transactions V2
POST /api/v1/cards/auth-transactions Authorization transactions
POST /api/v1/cards/auth-fee-transactions Authorization fee transactions
POST /api/v1/cards/3ds-transactions 3DS OTP / auth URL transactions
POST /api/v1/cards/simulate-auth Simulate authorization (sandbox only)

Cardholders

KYC onboarding and cardholder lifecycle. Cardholder creation is async — the initial response returns wait_audit and the final result arrives via webhook.

POST /api/v1/cardholders/occupations Supported occupation codes
POST /api/v1/cardholders/create-v2 Create cardholder — B2B or B2C model
POST /api/v1/cardholders/update-v2 Update cardholder (when status=reject)
POST /api/v1/cardholders/list List cardholders (paginated, filterable)
POST /api/v1/cardholders/update-email Update cardholder email (when status=pass_audit)

B2B vs B2C Model

FieldB2BB2C
cardHolderModel"B2B""B2C"
Common fields (name, address, mobile…)✅ Required✅ Required
gender, nationality, occupation✅ Required
idType, idNumber, idFrontId, idBackId, idHoldId✅ Required
kycVerification (provider, referenceId)Optional (required for type 111065)

Accounts

Merchant wallet accounts — balances, ledger history, and fund transfers between accounts.

GET /api/v1/accounts/assets Total assets overview
GET /api/v1/accounts/ Account list
GET /api/v1/accounts/single Single account details
GET /api/v1/accounts/transactions Ledger transaction history
POST /api/v1/accounts/create Create shared account
POST /api/v1/accounts/transfer Transfer funds between accounts

Work Orders

Submit and track platform work orders (e.g. card activation requests).

POST /api/v1/work-orders/ Submit a work order
GET /api/v1/work-orders/ List work orders

Webhooks — Overview

Several operations are asynchronous: the API returns an immediate pending status, and the final result is delivered later via webhook. Your server must poll the Webhook Events API to retrieve these results.

Step 1
You call the API
e.g. create cardholder
Step 2
Immediate response
status: wait_audit
Step 3
Platform reviews
minutes to hours
Step 4
Webhook stored
final status: pass_audit or reject
Step 5
You poll events
GET /api/v1/webhook-events

Async Operations (always poll for final result)

API CallInitial ResponseFinal via Event category
POST /cardholders/create-v2wait_auditcard_holder
POST /cardholders/update-v2wait_auditcard_holder
POST /cardholders/update-emailwait_auditcard_holder_change_email
POST /cards/activate-physicalpendingphysical_card
POST /cards/depositpendingcard_transaction
POST /cards/withdrawpendingcard_transaction
POST /cards/cancelpendingcard_transaction
Card purchase (external)card_auth_transaction
3DS triggered (external)card_3ds

Webhook Event Reference

categoryTriggerreference_id field
card_holderCardholder status changeholderId
card_holder_change_emailEmail update statusholderId
card_transactionDeposit / withdraw / cancel final resultorderNo
card_auth_transactionAuthorization — may push multiple times as status flowstradeNo
card_fee_patchAuthorization fee appliedtradeNo
card_3ds3DS OTP code / auth URL / activation codetradeNo
physical_cardPhysical card activation resultcardNo
workWork order status changeorderNo
wallet_transactionWallet deposit/withdrawalorderNo
wallet_transaction_v2Wallet transaction history V2orderNo

Cardholder Status Values

statusMeaning
wait_auditPending review — not final, keep polling
under_reviewIn review — not final, keep polling
pass_audit✅ Approved — final
reject❌ Rejected — final. Check description for reason

Polling Webhook Events

Use GET /api/v1/webhook-events to retrieve stored async results. Filter by category and reference_id for the specific operation you're waiting on.

Example: Poll for cardholder creation result

# Step 1 — create cardholder, get holderId from response
curl -X POST https://{api-domain}/sandbox/api/v1/cardholders/create-v2 \
  -H "X-API-KEY: wc_..." -d '{ "cardHolderModel": "B2C", ... }'
# Response: { "data": { "holderId": 124024, "status": "wait_audit" } }

# Step 2 — poll until status is pass_audit or reject
curl "https://{api-domain}/sandbox/api/v1/webhook-events?category=card_holder&reference_id=124024" \
  -H "X-API-KEY: wc_..."

Query Parameters

ParameterTypeDescription
categorystringFilter by event type (e.g. card_holder)
reference_idstringholderId, tradeNo, orderNo, or cardNo depending on category
merchant_order_nostringFilter by your own order number
statusstringFilter by status value (e.g. pass_audit)
fromdatetimeFilter from date. Format: Y-m-d H:i:s
todatetimeFilter to date. Format: Y-m-d H:i:s
per_pageintegerRecords per page. Max 100, default 15
pageintegerPage number

Sample Response

{
  "success": true,
  "code": 200,
  "data": {
    "total": 1,
    "data": [
      {
        "id": 5,
        "category":          "card_holder",
        "reference_id":     "124024",
        "merchant_order_no": "ORDER20250101000001",
        "status":           "pass_audit",
        "payload": {          // full raw payload from platform
          "holderId":    124024,
          "status":      "pass_audit",
          "description": "Approved"
        },
        "created_at": "2026-04-18T10:30:00.000000Z"
      }
    ]
  }
}
⚠️
Polling interval recommendation: Poll every 30–60 seconds. Stop once you receive a final status (pass_audit or reject). card_auth_transaction events may be pushed multiple times for the same tradeNo as status progresses.
For full interactive API reference with request/response schemas and a live testing console, visit the Swagger UI →