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.
/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
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 Status | code | Meaning | Action |
|---|---|---|---|
| 200 | 200 | Success | Process data |
| 400 | 400 | Bad request / business rule error | Check msg for details |
| 401 | 401 | Missing or invalid API key | Check your X-API-KEY header |
| 422 | 422 | Validation failed | data contains field-level errors |
| 429 | 429 | Rate limit exceeded | Wait and retry. See Rate Limiting |
| 502 | 502 | Upstream service error | Retry. 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.
/api/v1/common/regions Supported countries/regions/api/v1/common/cities City list with codes/api/v1/common/cities/hierarchical Cities grouped by region/api/v1/common/mobile-codes Supported phone area codes/api/v1/common/files/upload Upload KYC documents (multipart/form-data)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.
/api/v1/wallet/v2/coins Supported coins list/api/v1/wallet/v2/create?coinKey=USDT_BEP20&externalUserId=CUSTOMER_001 Return the funding wallet top-up address/api/v1/wallet/card-topup-orders Store a wallet deposit to card top-up mapping/api/v1/wallet/card-topup-orders/{id} Get one card top-up order status/api/v1/wallet/card-topup-orders?txHash=0x... Search card top-up orders/api/v1/wallet/v2/address-list List funding wallet top-up addresses/api/v1/wallet/v2/transactions Transaction history V2data.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.
/api/v1/cards/support-bins Supported card types and BINs/api/v1/cards/create-v2 Create a virtual card or create/register a physical card (V2)/api/v1/cards/activate-physical Activate a physical card/api/v1/cards/info Card details/api/v1/cards/sensitive Encrypted card number, expiry, CVV/api/v1/cards/balance Card balance/api/v1/cards/list List all cards (paginated)/api/v1/cards/update Update card label / settings/api/v1/cards/freeze Freeze card/api/v1/cards/unfreeze Unfreeze card/api/v1/cards/cancel Cancel (close) card/api/v1/cards/update-pin Update card PIN/api/v1/cards/note Update card note/api/v1/cards/deposit Deposit funds to card/api/v1/cards/withdraw Withdraw funds from card/api/v1/cards/purchase-transactions Purchase/debit transactions/api/v1/cards/operation-transactions-v2 Operation transactions V2/api/v1/cards/auth-transactions Authorization transactions/api/v1/cards/auth-fee-transactions Authorization fee transactions/api/v1/cards/3ds-transactions 3DS OTP / auth URL transactions/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.
/api/v1/cardholders/occupations Supported occupation codes/api/v1/cardholders/create-v2 Create cardholder — B2B or B2C model/api/v1/cardholders/update-v2 Update cardholder (when status=reject)/api/v1/cardholders/list List cardholders (paginated, filterable)/api/v1/cardholders/update-email Update cardholder email (when status=pass_audit)B2B vs B2C Model
| Field | B2B | B2C |
|---|---|---|
| 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.
/api/v1/accounts/assets Total assets overview/api/v1/accounts/ Account list/api/v1/accounts/single Single account details/api/v1/accounts/transactions Ledger transaction history/api/v1/accounts/create Create shared account/api/v1/accounts/transfer Transfer funds between accountsWork Orders
Submit and track platform work orders (e.g. card activation requests).
/api/v1/work-orders/ Submit a work order/api/v1/work-orders/ List work ordersWebhooks — 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.
Async Operations (always poll for final result)
| API Call | Initial Response | Final via Event category |
|---|---|---|
POST /cardholders/create-v2 | wait_audit | card_holder |
POST /cardholders/update-v2 | wait_audit | card_holder |
POST /cardholders/update-email | wait_audit | card_holder_change_email |
POST /cards/activate-physical | pending | physical_card |
POST /cards/deposit | pending | card_transaction |
POST /cards/withdraw | pending | card_transaction |
POST /cards/cancel | pending | card_transaction |
| Card purchase (external) | — | card_auth_transaction |
| 3DS triggered (external) | — | card_3ds |
Webhook Event Reference
| category | Trigger | reference_id field |
|---|---|---|
card_holder | Cardholder status change | holderId |
card_holder_change_email | Email update status | holderId |
card_transaction | Deposit / withdraw / cancel final result | orderNo |
card_auth_transaction | Authorization — may push multiple times as status flows | tradeNo |
card_fee_patch | Authorization fee applied | tradeNo |
card_3ds | 3DS OTP code / auth URL / activation code | tradeNo |
physical_card | Physical card activation result | cardNo |
work | Work order status change | orderNo |
wallet_transaction | Wallet deposit/withdrawal | orderNo |
wallet_transaction_v2 | Wallet transaction history V2 | orderNo |
Cardholder Status Values
| status | Meaning |
|---|---|
wait_audit | Pending review — not final, keep polling |
under_review | In 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
| Parameter | Type | Description |
|---|---|---|
category | string | Filter by event type (e.g. card_holder) |
reference_id | string | holderId, tradeNo, orderNo, or cardNo depending on category |
merchant_order_no | string | Filter by your own order number |
status | string | Filter by status value (e.g. pass_audit) |
from | datetime | Filter from date. Format: Y-m-d H:i:s |
to | datetime | Filter to date. Format: Y-m-d H:i:s |
per_page | integer | Records per page. Max 100, default 15 |
page | integer | Page 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"
}
]
}
}
pass_audit or reject). card_auth_transaction events may be pushed multiple times for the same tradeNo as status progresses.