EasyCards VCC Integration Guide#
Last updated: 2026-08-14
This guide covers the EasyCards virtual-card API and the four supporting account-query endpoints, request sequencing, resource states, Webhooks, and the downloadable OpenAPI and Postman contracts.
1. Environments and authentication#
1.1 Base URLs#
| Environment | Base URL |
|---|---|
| Sandbox | https://sandbox.easycards.io |
| Production | Shown in EasyCards Portal after production approval |
1.2 API Key#
Send the Payment API Key with the following header:
Authorization: Bearer <PAYMENT_API_KEY>
Content-Type: application/json
The permissions used by the VCC endpoints are:
| Permission | Operations |
|---|---|
payment.vcc.read |
Read products, customers, applications, cards, balances, top-ups, and transactions |
payment.vcc.customer.manage |
Create or update customers and upload private files |
payment.vcc.card.create |
Submit card applications |
payment.vcc.card.sensitive |
Retrieve RSA-encrypted card data |
payment.vcc.card.topup |
Submit card top-ups |
payment.vcc.card.withdraw |
Submit shared-card withdrawals |
payment.vcc.card.status |
Freeze and unfreeze cards |
2. Response and idempotency rules#
Successful response:
{
"code": 0,
"message": "OK",
"data": {}
}
Error response:
{
"code": "VALIDATION_ERROR",
"message": "One or more request fields are invalid.",
"data": null
}
Evaluate the HTTP status and top-level code first. For asynchronous resources, then evaluate the resource status:
application_statusfor card applications.topup_statusfor top-ups.withdrawal_statusfor shared-card withdrawals.resource_statusin freeze and unfreeze responses and status Webhooks.card_statusfor the current card state.
PENDING means processing. SUCCESS and FAIL are terminal.
Every write request contains a merchant-generated request_id:
- Length: 1–64 characters.
- Reuse the same value and the same request body when retrying after a network timeout.
- A reused
request_idwith different parameters returnsIDEMPOTENCY_CONFLICT. - Save the mapping from
request_idtocustomer_id,application_id,topup_id,withdrawal_id, or the affectedcard_id.
3. Accounts#
Account endpoints use the same Base URL and Bearer Token as the VCC endpoints. Account balances represent account-level funds and are separate from an individual card balance.
3.1 Current account#
GET /payment/account
The request has no path, query, or body fields. data.account returns merchant_id, account_id, account name and status, supported currencies, default currency, timezone, and timestamps.
View this operation in API Reference →
3.2 Account balances#
GET /payment/balances
The optional currency query field limits the response to one currency. Each item in data.balances contains:
| Field | Type | Meaning |
|---|---|---|
account_id |
string | Account identifier |
currency |
string | Uppercase currency code |
currency_type |
string | fiat or crypto |
balance |
decimal | Total account balance |
available |
decimal | Available balance |
frozen |
decimal | Frozen balance |
updated_at |
integer | Update time in Unix seconds |
View this operation in API Reference →
3.3 Deposits#
GET /payment/deposits
Optional query fields are currency, network, status, start_at, end_at, limit, and offset. data.deposits contains deposit records with account and deposit IDs, currency, network, transaction ID, amount, status, confirmations, reference, and timestamps. data.total and data.total_pages describe the result set.
View this operation in API Reference →
3.4 Ledger entries#
GET /payment/ledger
Optional query fields are currency, record_type, start_at, end_at, limit, offset, sort_by, and sort_order. data.entries contains ledger identifiers and types, voucher fields, currency, change amount, balance after the entry, reference, and creation time. data.total and data.total_pages describe the result set.
View this operation in API Reference →
4. Core sequence#
4.1 Card-issuance flow#
Solid lines represent synchronous HTTP requests or responses. Dashed lines represent asynchronous Webhooks sent by EasyCards. PENDING is a business status in a completed synchronous response; it does not mean that the HTTP request is still open.
sequenceDiagram
autonumber
participant M as Merchant system
participant E as EasyCards API
Note over M,E: Phase 1: Read the card-issuance requirements
M->>E: List products and issuance requirements · GET /payment/vcc/products
E->>M: [Synchronous response] product_code, card_mode, fees, limits, required_customer_fields
opt The product requires file fields
M->>E: Upload a customer file and obtain its identifier · POST /payment/vcc/files
E->>M: [Synchronous response] file_id
end
Note over M,E: Phase 2: Create the customer and submit the application
M->>E: Create the cardholder record · POST /payment/vcc/customers
E->>M: [Synchronous response] customer_id, customer_status
M->>E: Submit a card application · POST /payment/vcc/card-applications
E->>M: [Synchronous acceptance] application_id, application_status
Note over M,E: Phase 3: Receive status changes and query the current result
opt application_status = PENDING
E-->>M: [Asynchronous notification] vcc.application.updated · status or next_action changed
end
M->>E: Query the current application result · GET /payment/vcc/card-applications/{application_id}
E->>M: [Synchronous response] application_status, with card_id on success
opt application_status = SUCCESS
M->>E: Query card state and basic details · GET /payment/vcc/cards/{card_id}
E->>M: [Synchronous response] card_status and basic card details
end
4.2 Subsequent card operations#
Top-up, shared-card withdrawal, freeze, and unfreeze requests first return a synchronous acceptance result. If processing continues, the corresponding Webhook reports the later state change. Balance queries and sensitive-data retrieval complete within the current HTTP request.
sequenceDiagram
participant M as Merchant system
participant E as EasyCards API
opt Read card funds
M->>E: Query one card's current balance · GET /payment/vcc/cards/{card_id}/balance
E->>M: [Synchronous response] balance, available, frozen
end
opt Retrieve sensitive card data
M->>E: Retrieve RSA-encrypted card data · POST /payment/vcc/cards/sensitive
E->>M: [Synchronous response] encrypt_data
end
opt Top up a card or increase a shared-card limit
M->>E: Submit the amount through the unified top-up endpoint · POST /payment/vcc/cards/{card_id}/topups
E->>M: [Synchronous acceptance] topup_id, topup_status
E-->>M: [Asynchronous notification] vcc.topup.updated · top-up status changed
M->>E: Query the current top-up result · GET /payment/vcc/topups/{topup_id}
E->>M: [Synchronous response] topup_status, amount, and fee
end
opt Withdraw unused shared-card limit
M->>E: Submit a shared-card withdrawal · POST /payment/vcc/cards/{card_id}/withdrawals
E->>M: [Synchronous acceptance] withdrawal_id, withdrawal_status
E-->>M: [Asynchronous notification] vcc.withdrawal.updated · withdrawal status changed
end
opt Freeze or unfreeze a card
M->>E: Submit a card-state change · POST .../freeze or POST .../unfreeze
E->>M: [Synchronous acceptance] resource_status
E-->>M: [Asynchronous notification] vcc.card.updated · terminal result
M->>E: Query the card's current state · GET /payment/vcc/cards/{card_id}
E->>M: [Synchronous response] card_status
end
5. Products#
GET /payment/vcc/products
Use the response to select the current product_code and obtain:
- Card form,
card_mode, and settlement currency. - Opening, KYC, reversal, refund, cross-border, fixed 3DS, fixed platform-authorization, and top-up fee rules.
- Initial top-up snapshots.
- Minimum and maximum top-up amounts.
required_customer_fields.
Build additional_customer_data from the selected product’s required_customer_fields. For enum fields, submit accepted_values[].value.
Persist card_mode as the authoritative funding path. PREPAID_CARD top-ups debit the account wallet associated with the current API key. BUDGET_CARD top-ups are shared-card limit increases funded from the shared account bound to the card. Both modes use the same top-up endpoints and vcc.topup.updated event.
6. Private files#
When a product requires document or selfie files:
POST /payment/vcc/files
Content-Type: multipart/form-data
The required multipart field name is file. Supported file types are JPG/JPEG, PNG, and PDF. The maximum size of one file is 2 MiB. Save the returned file_id and submit it in the matching key inside additional_customer_data.
7. Customers#
Create:
POST /payment/vcc/customers
Required customer fields:
| Field | Rule |
|---|---|
request_id |
1–64 characters |
first_name, last_name |
1–128 characters |
gender |
male, female, or unknown |
email |
Valid email, up to 256 characters |
phone_country_code |
International dialing code |
mobile_number |
ASCII digits only; send the dialing code separately |
date_of_birth |
yyyy-MM-dd |
city, state_or_province |
Up to 128 characters |
residence_country, nationality |
Uppercase ISO 3166-1 alpha-2 code |
street_address |
After trimming, 2–40 ASCII characters matching ^[A-Za-z0-9 ]+$; only letters, digits, and ordinary spaces are allowed, and hyphens and other symbols are not allowed |
postal_code |
Up to 32 characters |
additional_customer_data |
Product-specific fields, when required |
Example:
{
"request_id": "merchant-customer-C202607280001",
"first_name": "Alex",
"last_name": "Chen",
"gender": "male",
"email": "alex.chen@example.com",
"phone_country_code": "+86",
"mobile_number": "13800138000",
"date_of_birth": "1990-01-02",
"city": "Shanghai",
"state_or_province": "Shanghai",
"residence_country": "CN",
"nationality": "CN",
"street_address": "100 Century Avenue",
"postal_code": "200120",
"additional_customer_data": {
"id_type": "PASSPORT",
"id_number": "TR1234567"
}
}
Read and update:
GET /payment/vcc/customers?limit=20&offset=0
GET /payment/vcc/customers/{customer_id}
PATCH /payment/vcc/customers/{customer_id}
Customer responses return the current profile in data.customer. List responses return data.customers and data.total.
8. Card applications#
Submit:
POST /payment/vcc/card-applications
{
"request_id": "merchant-card-O202607280001",
"customer_id": "cus_0123456789abcdef",
"product_code": "1103"
}
Save application_id from the response. Query the current result with:
GET /payment/vcc/card-applications/{application_id}
GET /payment/vcc/card-applications?limit=20&offset=0
Application handling:
| State | Handling |
|---|---|
PENDING without next_action |
Wait for a Webhook or query again |
PENDING + COMPLETE_LIVENESS |
Direct the cardholder to complete the required liveness action |
PENDING + ADD_FUNDS |
Use required_account_balance, required_balance_currency, and expires_at |
SUCCESS |
Save the non-empty card_id |
FAIL |
Save failure_code and failure_message |
Application detail responses include open_fee_amount, kyc_fee_amount, total_debit_amount, and settlement_currency snapshots. The KYC fee is charged only when card opening succeeds.
9. Cards and sensitive data#
Read cards:
GET /payment/vcc/cards?limit=20&offset=0
GET /payment/vcc/cards/{card_id}
GET /payment/vcc/cards/{card_id}/balance
Card list and detail responses include card_mode: PREPAID_CARD or BUDGET_CARD. Treat it as the card's immutable funding-mode snapshot for subsequent top-ups and reconciliation. accounting_currency identifies the account currency used for opening fees and shared-account ledger deductions when applicable.
The balance response is a snapshot. Use updated_at to determine its timestamp. It also returns accounting_currency when shared-account ledger deductions use an account currency distinct from the card balance currency.
Sensitive card data:
POST /payment/vcc/cards/sensitive
{
"card_id": "card_0123456789abcdef"
}
If public_key is supplied, it overrides the current API key's configured key for this request only. Otherwise, the public key configured for the current API key in the merchant Portal is used.
The RSA requirements in the current contract are:
- RSA 1024-bit key pair.
- Submit the Base64 content of the X.509/SPKI public key without PEM headers or whitespace.
- Keep the PKCS#8 private key in the merchant’s secure environment.
- Decrypt the returned ciphertext using RSA PKCS#1 v1.5.
- Do not write full PAN, CVV, decrypted payloads, or private keys to logs.
10. Top-ups and shared-card withdrawals#
10.1 Top-ups#
The same endpoint selects the business path from the card's card_mode:
card_mode |
Business meaning | Principal and fee source |
|---|---|---|
PREPAID_CARD |
Top up a prepaid card | Account wallet associated with the current API key |
BUDGET_CARD |
Increase a shared card's available limit | Shared account bound to the card |
Both modes return the same top-up object and use the same list, detail, and vcc.topup.updated flow. Top-up principal is not duplicated as a card transaction.
POST /payment/vcc/cards/{card_id}/topups
{
"request_id": "merchant-topup-T202607280001",
"topup_amount": "10.00"
}
topup_amount is a positive string with at most two decimal places and must be within the selected product’s limits. Save the returned topup_id.
Query:
GET /payment/vcc/topups/{topup_id}
GET /payment/vcc/topups?limit=20&offset=0
Use topup_status as the business status. The response includes the principal, fee, total debit, settlement currency, and timestamps.
10.2 Shared-card withdrawal#
This operation withdraws unused available limit from a card_mode = BUDGET_CARD shared card. Prepaid cards are not supported. After submission, query the withdrawal list or detail endpoint for the current status; vcc.withdrawal.updated still reports asynchronous status changes.
POST /payment/vcc/cards/{card_id}/withdrawals
Permission: payment.vcc.card.withdraw
{
"request_id": "merchant-withdrawal-W202608130001",
"merchant_withdrawal_no": "WD202608130001",
"withdrawal_amount": "10.00"
}
request_id is the 1–64 character API idempotency key. merchant_withdrawal_no is a 1–64 character merchant order number that must be unique within the merchant account and may contain letters, digits, _, ., :, or -. withdrawal_amount must be positive, have at most two decimal places, and not exceed the card's unused available limit.
Accepted response:
{
"code": 0,
"message": "OK",
"data": {
"withdrawal": {
"request_id": "merchant-withdrawal-W202608130001",
"withdrawal_id": "wd_0123456789abcdef",
"merchant_withdrawal_no": "WD202608130001",
"card_id": "card_0123456789abcdef",
"withdrawal_status": "PENDING",
"withdrawal_amount": "10.00",
"settlement_currency": "USD",
"created_at": 1786582800,
"updated_at": 1786582800
}
}
}
PENDING means accepted, not successful. Save withdrawal_id and merchant_withdrawal_no, then use the signed vcc.withdrawal.updated event's resource_status to process terminal SUCCESS or FAIL.
Replay the same request_id only with the same parameters. Reusing merchant_withdrawal_no with the same card and amount returns the original withdrawal; using it with a different card or amount returns 409 CARD_WITHDRAWAL_ORDER_CONFLICT. A concurrent card-limit operation returns 409 CARD_OPERATION_IN_PROGRESS; a non-shared card returns 422 CARD_WITHDRAWAL_NOT_SUPPORTED.
View this operation in API Reference →
10.3 Query shared-card withdrawals#
After submitting a shared-card withdrawal, query the current merchant-account records with optional order, card, status, and pagination filters:
GET /payment/vcc/withdrawals?merchant_withdrawal_no=WD202608130001&card_id=card_0123456789abcdef&withdrawal_status=PENDING&limit=20&offset=0
Permission: payment.vcc.read
All query parameters are optional. merchant_withdrawal_no is the merchant order number, card_id is the platform card identifier, and withdrawal_status accepts PENDING, SUCCESS, or FAIL. limit defaults to 20 (1–200) and offset defaults to 0.
The response contains data.withdrawals and data.total. Each withdrawal has the same fields as the submit response, including withdrawal_id, merchant_withdrawal_no, withdrawal_status, withdrawal_amount, settlement_currency, and timestamps.
Query one withdrawal by its platform identifier:
GET /payment/vcc/withdrawals/{withdrawal_id}
Permission: payment.vcc.read. The response contains data.withdrawal; a missing record or a record outside the current merchant account returns 404 CARD_WITHDRAWAL_NOT_FOUND.
The query endpoints return the current state. Webhooks report asynchronous changes; after receiving a Webhook, query the detail endpoint again when confirmation is required.
View the withdrawal list in API Reference →
View the withdrawal detail in API Reference →
11. Freeze and unfreeze#
Freeze:
POST /payment/vcc/cards/{card_id}/freeze
Unfreeze:
POST /payment/vcc/cards/{card_id}/unfreeze
Request body:
{
"request_id": "merchant-freeze-F202607280001"
}
Accepted response data:
{
"request_id": "merchant-freeze-F202607280001",
"card_id": "card_0123456789abcdef",
"resource_status": "PENDING"
}
Use vcc.card.updated Webhooks or GET /payment/vcc/cards/{card_id} to confirm the final card state.
12. Transactions#
12.1 Public transaction model#
vcc.transaction.updated exposes only these four transaction types:
transaction_type |
Meaning | Original transaction link |
|---|---|---|
auth |
Purchase authorization bill. Authorization, settlement, and purchase failure update the same bill; no separate settlement type is exposed | No |
void |
Pre-settlement reversal or authorization release | Yes, through original_transaction_id |
refund |
Post-settlement refund | Yes, through original_transaction_id |
fee |
Standalone fee transaction created only after a card-management or 3DS fee is successfully collected; other fees are not separate fee transactions |
No |
Only these transaction statuses are returned:
transaction_status |
Meaning |
|---|---|
authorized |
Authorized but not finally settled |
failed |
Currently failed; a later upstream correction may still produce a succeed update |
succeed |
Completed; do not regress it with an older authorized or failed event |
A typical purchase moves from auth / authorized to auth / succeed or auth / failed. Successful settlement retains the original transaction_id and updates only the status, settlement amount, and aggregate fee.
Key transaction-query fields:
| Field | Meaning |
|---|---|
transaction_id |
Stable merchant transaction ID; unchanged from authorization through settlement |
card_id |
Platform card ID |
card_last4 |
Last four card digits when a safe masked PAN is available |
product_code |
Card product code |
three_ds_id |
Related challenge ID for a standalone 3DS fee; omitted otherwise |
deduction_source |
Actual fee funding source, card or merchant_wallet; omitted otherwise |
transaction_type |
auth, void, refund, or fee |
transaction_status |
authorized, failed, or succeed |
fee_type |
card_management for a standalone card-management fee or three_ds for a standalone 3DS fee |
transaction_amount / transaction_currency |
Original purchase or business amount and currency |
authorization_amount / authorization_currency |
Final platform authorization amount and currency |
fee_amount / fee_currency |
Merchant-facing aggregate confirmed fee and currency; the current fee currency is USDT |
settlement_amount / settlement_currency |
Final platform settlement/debit amount and currency; normally 0.00 before settlement and updated to the final value when settlement completes |
merchant_name / merchant_descriptor |
Merchant name and statement descriptor when available |
merchant_country / merchant_category_code |
Merchant country or region and MCC when available |
original_transaction_id |
Original purchase transaction ID for a void or refund |
occurred_at |
Transaction time in Unix seconds |
fee_amount is the merchant-visible fee aggregate returned for the transaction. Unconfigured or inapplicable fees are not included; merchant APIs and Webhooks do not return the fee breakdown.
After settlement, use settlement_amount as the final debit amount. fee_amount is a display aggregate only; do not recompute or add it again from other amount fields. Treat the platform's final transaction snapshot as authoritative.
A standalone card-management fee uses fee_type = card_management; a successfully collected 3DS fee uses fee_type = three_ds. Both use transaction_type = fee, return the charge in transaction_amount and settlement_amount, and keep fee_amount at 0.00 to prevent double counting. A failed or unknown 3DS deduction stays in the fee task and does not create a successful transaction; the transaction appears only after recovery succeeds.
12.2 List transactions for one card#
GET /payment/vcc/cards/{card_id}/transactions?limit=20&offset=0
Permission: payment.vcc.read
Optional filters are transaction_type (auth, void, refund, or fee), transaction_status (authorized, failed, or succeed), start_at, end_at, limit, and offset. Type and status matching is case-insensitive.
12.3 List all VCC transactions#
GET /payment/vcc/transactions?limit=20&offset=0
Permission: payment.vcc.read
Supported filters are transaction_id, card_id, product_code, transaction_type, transaction_status, start_at, end_at, limit, and offset. Type and status matching is case-insensitive.
The query result is the reconciliation authority. Webhooks and query responses both use snake_case and keep shared field names aligned. After receiving a notification, upsert the local snapshot by transaction_id and query the latest record when reconciliation is required.
| Query field | Webhook field |
|---|---|
transaction_id |
data.transaction_id |
card_id |
data.card_id |
product_code |
data.product_code |
transaction_type |
data.transaction_type |
transaction_status |
data.transaction_status |
transaction_amount / transaction_currency |
data.transaction_amount / data.transaction_currency |
authorization_amount / authorization_currency |
data.authorization_amount / data.authorization_currency |
settlement_amount / settlement_currency |
data.settlement_amount / data.settlement_currency |
fee_amount / fee_currency |
data.fee_amount / data.fee_currency |
original_transaction_id |
data.original_transaction_id |
12.4 Simulate a transaction (Sandbox/local only)#
POST /payment/vcc/transactions/simulate
Use this endpoint to test transaction accounting, card-balance changes, fee processing, and vcc.transaction.updated Webhooks without calling the card issuer. It is disabled in production, where it returns 403 CARD_TRANSACTION_SIMULATION_DISABLED.
The request still requires a normal Payment API Bearer Token and validates the card against the current API Key account scope, but it has no separately assignable business permission.
Do not send merchant_data. The simulator automatically uses the fixed test merchant Local transaction simulation, MCC 5734, and country code US. The HTTP response exposes these as flat merchant_name / merchant_category_code / merchant_country fields, while the transaction Webhook uses data.merchant_data.name / category_code / country.
| Field | Required | Meaning |
|---|---|---|
request_id |
Yes | 1–64 character idempotency key; an exact replay returns the original transaction |
card_id |
Yes | An ACTIVE card in the current account |
original_transaction_id |
No | Existing local simulated bill to link settlement, reversal, or refund; use it with AUTH to settle |
transaction_type |
Yes | Unified bill action: AUTH, VOID, or REFUND; AUTH without an original creates authorization, while AUTH with an original settles it; uppercase only |
amount |
Yes | Positive USD amount as a string with at most two decimal places |
Simulator action (transaction_type) |
Merchant-visible result | Principal or authorization effect | Fee presentation |
|---|---|---|---|
AUTH |
auth / authorized |
Decreases card availability and creates an authorization hold | Assesses applicable ordinary fees from the active product configuration and writes them to fee_amount; no standalone fee transaction |
AUTH with original_transaction_id |
auth / succeed |
Debits settled principal and updates the original auth |
Updates the same bill's final fee_amount and settlement_amount; no separate settlement or fee transaction |
VOID |
void / succeed |
Releases outstanding local simulated authorization | Any applicable reversal fee is written to this void bill's fee_amount; no standalone fee transaction |
REFUND |
refund / succeed |
Returns remaining local simulated settled principal | Any applicable refund fee is written to this refund bill's fee_amount; no standalone fee transaction |
Fees are not simulator request actions. The simulator validates only the bill lifecycle; whether a fee is charged is determined by the active card-product configuration. Unconfigured or zero fees are not charged. An ordinary purchase sends at most two transaction Webhooks: auth / authorized at authorization and auth / succeed on the same transaction_id at settlement; the fee fields are carried in the transaction snapshots, with no separate ordinary-fee Webhook. 3DS fees are triggered only by a real 3DS event.
The request transaction_type is a simulator action, not the final merchant transaction_type. Use a new request_id for every step. For a later action, pass the previous response's data.transaction.transaction_id as original_transaction_id.
Step 1: simulate a purchase authorization#
{
"request_id": "merchant-sim-A202608140001",
"card_id": "card_0123456789abcdef",
"transaction_type": "AUTH",
"amount": "10.00"
}
Key response fields:
{
"data": {
"transaction": {
"transaction_id": "sim_auth_934dea33",
"transaction_type": "auth",
"transaction_status": "authorized",
"transaction_amount": "10.00",
"transaction_currency": "USD",
"authorization_amount": "10.00",
"authorization_currency": "USD",
"fee_amount": "0.00",
"fee_currency": "USDT",
"settlement_amount": "0.00",
"settlement_currency": "USD",
"merchant_name": "Local transaction simulation",
"merchant_descriptor": "Local transaction simulation",
"merchant_country": "US",
"merchant_category_code": "5734"
}
}
}
Save sim_auth_934dea33 for settlement or void testing.
Step 2A: settle the original authorization#
{
"request_id": "merchant-sim-C202608140002",
"card_id": "card_0123456789abcdef",
"original_transaction_id": "sim_auth_934dea33",
"transaction_type": "AUTH",
"amount": "10.00"
}
The response retains transaction_id = sim_auth_934dea33, changes it to transaction_type = auth and transaction_status = succeed, and sends the second complete transaction Webhook for the same data.transaction_id with the final fee_amount and settlement_amount. It does not create a separate settlement bill or ordinary fee transaction. Unconfigured fees are not charged.
Step 2B: void an unsettled authorization#
This is an alternative to step 2A and must use another simulated authorization that is still authorized:
{
"request_id": "merchant-sim-V202608140003",
"card_id": "card_0123456789abcdef",
"original_transaction_id": "sim_auth_another",
"transaction_type": "VOID",
"amount": "10.00"
}
The response creates a new void / succeed transaction with original_transaction_id = sim_auth_another.
Step 3: refund a settled purchase#
{
"request_id": "merchant-sim-R202608140004",
"card_id": "card_0123456789abcdef",
"original_transaction_id": "sim_auth_934dea33",
"transaction_type": "REFUND",
"amount": "4.00"
}
The response creates a new refund / succeed transaction with original_transaction_id = sim_auth_934dea33 and, on success, settlement_amount = 4.00.
Every successful response uses the merchant transaction structure in this chapter. VOID cannot exceed releasable authorization, and REFUND cannot exceed refundable principal. Simulation never links to or modifies a real issuer transaction.
Common simulation errors:
| HTTP | code |
Meaning |
|---|---|---|
403 |
CARD_TRANSACTION_SIMULATION_DISABLED |
The endpoint is disabled in production |
404 |
ORIGINAL_TRANSACTION_NOT_FOUND |
The original simulated transaction does not exist under the current account and card |
409 |
ORIGINAL_TRANSACTION_INVALID |
The original type, state, or remaining amount cannot accept the requested action |
409 |
CARD_STATUS_NOT_ALLOWED |
The card is not in a state that allows simulation |
422 |
INSUFFICIENT_CARD_BALANCE |
Card balance, releasable authorization, or refundable principal is insufficient |
The principal transaction is committed locally and emits the normal vcc.transaction.updated Webhook. It updates prepaid-card balance or shared-card availability, and any configured positive fee still uses the normal fee-processing, card-deduction, and shared-account collection paths. Treat this as a write that changes test-environment fund projections, not as a response-only preview.
View this operation in API Reference →
13. Webhooks#
13.1 Configuration and subscriptions#
Configure a public HTTPS callback URL, the Webhook Secret, and the VCC event subscription. Subscribing to vcc.* is equivalent to subscribing to:
vcc.application.updated
vcc.card.updated
vcc.topup.updated
vcc.withdrawal.updated
vcc.transaction.updated
vcc.3ds.required
Save the secret returned when the Webhook is created or rotated. This is the HMAC key used for verification. It is not returned again in the Webhook list; rotate the secret if it is lost.
13.2 Event catalog#
| Event | Subtype / transaction type | Result | Reconciliation ID |
|---|---|---|---|
vcc.application.updated |
KYC_REQUIRED |
Liveness action required | application_id |
vcc.application.updated |
FUNDS_REQUIRED |
Account funds required | application_id |
vcc.application.updated |
CARD_READY |
Card is available | application_id, card_id |
vcc.application.updated |
APPLICATION_FAILED |
Application failed | application_id |
vcc.card.updated |
CARD_FROZEN |
Freeze succeeded | card_id |
vcc.card.updated |
CARD_UNFROZEN |
Unfreeze succeeded | card_id |
vcc.card.updated |
CARD_FREEZE_FAILED |
Freeze failed | card_id |
vcc.card.updated |
CARD_UNFREEZE_FAILED |
Unfreeze failed | card_id |
vcc.topup.updated |
NORMAL_TOPUP |
Top-up status changed | topup_id |
vcc.withdrawal.updated |
CARD_WITHDRAWAL |
Shared-card withdrawal status changed | withdrawal_id, merchant_withdrawal_no |
vcc.transaction.updated |
data.transaction_type is auth, void, refund, or fee |
Transaction created or changed | data.transaction_id, data.card_id |
vcc.3ds.required |
CHALLENGE_REQUIRED |
3DS code is required | three_ds_id |
Top-up principal is not emitted as a card transaction. Read the top-up state from vcc.topup.updated and the top-up query endpoint. Standalone fee transactions currently include card-management fees and successfully collected 3DS fees.
All VCC events use snake_case. vcc.transaction.updated keeps its dedicated safe data snapshot structure, documented in section 13.9.
13.3 Headers and signature verification#
All VCC events use one delivery-header contract. Every VCC Webhook uses Content-Type, X-Delivery-Id, X-Webhook-Event, X-Webhook-Id, and X-Webhook-Signature.
| Header | Meaning |
|---|---|
Content-Type |
application/json |
X-Webhook-Signature |
Lowercase hexadecimal HMAC-SHA256 signature of the raw request body |
X-Webhook-Id |
Webhook configuration ID |
X-Delivery-Id |
Delivery record ID |
X-Webhook-Event |
event_type |
After creating or rotating a Webhook, verify with the secret returned by the API or finally shown in the Portal. Do not use the original custom Secret submitted in the create request directly.
expected_signature = hex(HMAC_SHA256(raw_request_body, webhook_secret))
Read and retain the original body bytes, calculate the signature before parsing or reserializing JSON, and compare signatures in constant time. On verification failure, return a non-2xx response and do not update business state.
13.4 Processing, acknowledgement, and retry rules#
- Verify the HMAC signature against the original body.
- Select the payload contract using
X-Webhook-Event. - For transaction events, validate
event_type,data.transaction_id, anddata.card_id; for other events, validateevent_type,event_subtype, andaccount_id. - Insert
event_idunder a unique constraint. - Return
2xximmediately for an already persisted event ID. - Upsert transaction events by
data.transaction_id. For withdrawal events, updateresource_statusidempotently bywithdrawal_id; for other events except 3DS, query the referenced resource for its current state. - Update local state transactionally.
- Return
2xxonly after the event is safely persisted.
Delivery rules:
| Rule | Current behavior |
|---|---|
| Successful acknowledgement | Any HTTP 2xx |
| First delivery | Immediate |
| Maximum deliveries | 1 initial delivery plus up to 9 retries; 10 total |
| Default retry intervals | 1, 2, 5, 10, 20, 40, 80, 240, and 1020 minutes |
| Default cumulative window | About 23 hours 38 minutes |
| Custom-plan hard limit | 72 hours |
| Duplicate delivery | The same event_id is reused |
| Ordering | Delivery order is not guaranteed |
| State authority | Use the current resource query result; Webhooks report asynchronous changes, and a withdrawal detail query can confirm the received event |
Network errors, timeouts, and non-2xx responses are failed deliveries and enter the retry schedule. Never log verification_code in normal application logs, errors, or monitoring labels.
13.5 Application event examples#
KYC_REQUIRED:
{
"event_id": "vcc_evt_0123456789abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "KYC_REQUIRED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"product_code": "1103",
"application_id": "app_0123456789abcdef",
"resource_status": "PENDING",
"next_action": {
"action_type": "COMPLETE_LIVENESS"
},
"occurred_at": 1784995200
}
FUNDS_REQUIRED:
{
"event_id": "vcc_evt_0a23456789abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "FUNDS_REQUIRED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"product_code": "1103",
"application_id": "app_0123456789abcdef",
"resource_status": "PENDING",
"next_action": {
"action_type": "ADD_FUNDS",
"required_account_balance": "6.01",
"required_balance_currency": "USDT",
"expires_at": 1785254400
},
"occurred_at": 1784995300
}
CARD_READY:
{
"event_id": "vcc_evt_1234567890abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "CARD_READY",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"application_id": "app_0123456789abcdef",
"customer_id": "cus_0123456789abcdef",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"masked_card_number": "409636******2420",
"resource_status": "SUCCESS",
"occurred_at": 1784995500
}
APPLICATION_FAILED:
{
"event_id": "vcc_evt_2345678901abcdef",
"event_type": "vcc.application.updated",
"event_subtype": "APPLICATION_FAILED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-card-O202607280001",
"product_code": "1103",
"application_id": "app_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784995500
}
13.6 Card event examples#
Successful freeze:
{
"event_id": "vcc_evt_3456789012abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_FROZEN",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-freeze-F202607280001",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "SUCCESS",
"occurred_at": 1784995800
}
Successful unfreeze:
{
"event_id": "vcc_evt_3567890123abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_UNFROZEN",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-unfreeze-U202607280001",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "SUCCESS",
"occurred_at": 1784995900
}
Failed freeze:
{
"event_id": "vcc_evt_3678901234abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_FREEZE_FAILED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-freeze-F202607280002",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784996000
}
Failed unfreeze:
{
"event_id": "vcc_evt_3789012345abcdef",
"event_type": "vcc.card.updated",
"event_subtype": "CARD_UNFREEZE_FAILED",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-unfreeze-U202607280002",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784996100
}
Freeze and unfreeze Webhooks are terminal only: they send SUCCESS or FAIL, not PENDING.
13.7 Top-up event examples#
event_subtype is always NORMAL_TOPUP. resource_status is PENDING, SUCCESS, or FAIL.
Pending:
{
"event_id": "vcc_evt_4567890123abcdef",
"event_type": "vcc.topup.updated",
"event_subtype": "NORMAL_TOPUP",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-topup-T202607280001",
"product_code": "1103",
"topup_id": "top_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"resource_status": "PENDING",
"occurred_at": 1784995700
}
Success:
{
"event_id": "vcc_evt_4678901234abcdef",
"event_type": "vcc.topup.updated",
"event_subtype": "NORMAL_TOPUP",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-topup-T202607280001",
"product_code": "1103",
"topup_id": "top_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"resource_status": "SUCCESS",
"occurred_at": 1784995800
}
Failure:
{
"event_id": "vcc_evt_4789012345abcdef",
"event_type": "vcc.topup.updated",
"event_subtype": "NORMAL_TOPUP",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-topup-T202607280001",
"product_code": "1103",
"topup_id": "top_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"resource_status": "FAIL",
"failure_code": "<failure_code>",
"failure_message": "<failure_message>",
"occurred_at": 1784995800
}
13.8 Shared-card withdrawal event example#
event_subtype is always CARD_WITHDRAWAL. resource_status is PENDING, SUCCESS, or FAIL. Terminal success example:
{
"event_id": "vcc_evt_5890123456abcdef",
"event_type": "vcc.withdrawal.updated",
"event_subtype": "CARD_WITHDRAWAL",
"event_version": "v1",
"account_id": "acct_example",
"request_id": "merchant-withdrawal-W202608130001",
"product_code": "1103",
"card_id": "card_0123456789abcdef",
"withdrawal_id": "wd_0123456789abcdef",
"merchant_withdrawal_no": "WD202608130001",
"withdrawal_amount": "10.00",
"settlement_currency": "USD",
"resource_status": "SUCCESS",
"occurred_at": 1786582860
}
Failure events also contain failure_code and failure_message. Deduplicate by event_id, update by withdrawal_id, and never let a late PENDING event overwrite terminal SUCCESS or FAIL.
13.9 Transaction event example#
Transaction events use snake_case and carry a safe bill snapshot under data. They do not include event_version, account_id, fee components, or internal financial journal fields. Every transaction notification includes data.card_id and data.product_code; a standalone 3DS fee also includes its actual deduction source.
| Field | Meaning |
|---|---|
event_id |
Snapshot-event deduplication key; unchanged across retries of the same delivery |
event_type |
Always vcc.transaction.updated |
occurred_at |
Event time in RFC 3339 format |
data.transaction_id |
Stable transaction ID; unchanged from purchase authorization through settlement |
data.card_id / data.product_code |
Platform card ID and product code; included in every transaction notification |
data.card_last4 |
Last four card digits when safely available |
data.three_ds_id |
Challenge ID related to a standalone 3DS fee |
data.deduction_source |
Actual 3DS fee funding source: card or merchant_wallet |
data.transaction_type |
auth, void, refund, or fee |
data.fee_type |
card_management for a standalone card-management fee or three_ds for a standalone 3DS fee |
data.transaction_status |
authorized, failed, or succeed |
data.transaction_amount / data.transaction_currency |
Original purchase or business amount and currency |
data.authorization_amount / data.authorization_currency |
Final platform authorization amount and currency |
data.settlement_amount / data.settlement_currency |
Final platform settlement/debit amount and currency; it can be 0.00 before settlement |
data.fee_amount / data.fee_currency |
Merchant-visible fee aggregate and currency; the fee breakdown is not returned |
data.original_transaction_id |
Original purchase ID for a void or refund; omitted otherwise |
data.merchant_data |
Merchant name, MCC, city, and country or region; omitted when unavailable |
data.authorization_code |
Authorization code; omitted when unavailable |
data.transaction_time |
Transaction time in RFC 3339 format |
data.updated_time |
Current bill snapshot update time in RFC 3339 format |
Display rules by business step:
| Step | data.transaction_type |
data.transaction_status |
Key amounts | Relationship |
|---|---|---|---|---|
| Purchase authorized | auth |
authorized |
settlement_amount is normally 0.00; fee_amount is the currently confirmed applicable ordinary-fee aggregate |
Purchase transaction_id |
| Purchase authorization failed | auth |
failed |
Current known amounts and aggregate fee | Same transaction_id as the authorization attempt |
| Purchase settled | auth |
succeed |
settlement_amount, settlement_currency, and fee_amount are updated to final values |
Same authorization transaction_id; no separate settlement bill or ordinary fee transaction |
| Authorization voided | void |
succeed or failed |
Authorized and settlement amounts are 0.00; any reversal fee is in this void bill's fee_amount |
New transaction_id plus original_transaction_id |
| Post-settlement refund | refund |
succeed or failed |
On success, settlement_amount is the refund amount; any refund fee is in this refund bill's fee_amount |
New transaction_id plus original_transaction_id |
| Card-management fee | fee |
succeed |
transaction_amount and settlement_amount are the card fee; fee_amount is 0.00 |
fee_type = card_management |
| 3DS fee collected | fee |
succeed |
transaction_amount and settlement_amount are the 3DS fee; fee_amount is 0.00 |
fee_type = three_ds; transaction_id equals the 3DS event's fee_transaction_id |
Purchase authorization example (real channel callback):
The ANTHROPIC* CLAUDE SUB value below is an illustrative upstream merchant record, not a local-simulation response. A simulated transaction Webhook must use Local transaction simulation, MCC 5734, and country code US in data.merchant_data.
{
"event_id": "vcc_evt_6789012345abcdef",
"event_type": "vcc.transaction.updated",
"occurred_at": "2026-08-24T10:20:15Z",
"data": {
"transaction_id": "934dea33-6ee0-44a0-baf8-fb36b4d2fe6d",
"card_id": "card_0123456789abcdef",
"product_code": "1103",
"transaction_type": "auth",
"transaction_status": "authorized",
"transaction_amount": "16.20",
"transaction_currency": "GBP",
"authorization_amount": "22.57",
"authorization_currency": "USD",
"settlement_amount": "0.00",
"settlement_currency": "USD",
"fee_amount": "0.52",
"fee_currency": "USDT",
"merchant_data": {
"name": "ANTHROPIC* CLAUDE SUB",
"category_code": "5734",
"city": "SAN FRANCISCO",
"country": "US"
},
"authorization_code": "76U47U",
"transaction_time": "2026-08-24T10:20:15Z",
"updated_time": "2026-08-24T10:20:16Z"
}
}
After settlement, EasyCards sends another complete snapshot with a new event_id and the same data.transaction_id, for example:
This example only shows the final settled bill snapshot. Merchants should use the returned settlement_amount as the actual debit amount and must not recompute it from authorization_amount and fee_amount.
{
"event_id": "vcc_evt_7890123456abcdef",
"event_type": "vcc.transaction.updated",
"occurred_at": "2026-08-25T03:12:40Z",
"data": {
"transaction_id": "934dea33-6ee0-44a0-baf8-fb36b4d2fe6d",
"card_id": "card_0123456789abcdef",
"product_code": "1103",
"transaction_type": "auth",
"transaction_status": "succeed",
"transaction_amount": "16.20",
"transaction_currency": "GBP",
"authorization_amount": "22.57",
"authorization_currency": "USD",
"settlement_amount": "22.81",
"settlement_currency": "USD",
"fee_amount": "0.52",
"fee_currency": "USDT",
"merchant_data": {
"name": "ANTHROPIC* CLAUDE SUB",
"category_code": "5734",
"city": "SAN FRANCISCO",
"country": "US"
},
"authorization_code": "76U47U",
"transaction_time": "2026-08-24T10:20:15Z",
"updated_time": "2026-08-25T03:12:40Z"
}
}
Deduplicate first by event_id, then upsert the local transaction snapshot by data.transaction_id. A real snapshot change creates a new event_id; retries reuse the existing one. Delivery order is not guaranteed. Do not let a late authorized overwrite failed or succeed, and do not let failed overwrite an existing succeed. When status or amount data conflicts, use the latest transaction-query result as the reconciliation authority.
13.10 3DS event example#
{
"event_id": "vcc_evt_7890123456abcdef",
"event_type": "vcc.3ds.required",
"event_subtype": "CHALLENGE_REQUIRED",
"event_version": "v1",
"account_id": "acct_example",
"product_code": "1103",
"three_ds_id": "3ds_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"card_last4": "4242",
"resource_status": "REQUIRED",
"verification_code": "123456",
"transaction_amount": "88.00",
"transaction_currency": "USD",
"merchant_name": "Example Store",
"merchant_country": "SG",
"merchant_category_code": "5411",
"fee_transaction_id": "txn_fee_3ds_fee_0123456789abcdef",
"fee_type": "three_ds",
"assessed_fee_amount": "0.37",
"fee_currency": "USDT",
"occurred_at": 1784995900
}
verification_code is returned directly under the current contract and is not RSA-encrypted. Verify the HMAC signature before reading or processing it. assessed_fee_amount is an assessment snapshot, not proof that the fee was collected.
After the card deduction or merchant-wallet fallback actually succeeds, the platform sends a standalone fee transaction with the same fee_transaction_id:
{
"event_id": "vcc_evt_89abcdef01234567",
"event_type": "vcc.transaction.updated",
"occurred_at": "2026-08-24T12:00:02Z",
"data": {
"transaction_id": "txn_fee_3ds_fee_0123456789abcdef",
"card_id": "card_0123456789abcdef",
"card_last4": "4242",
"product_code": "1103",
"three_ds_id": "3ds_0123456789abcdef",
"deduction_source": "card",
"transaction_type": "fee",
"fee_type": "three_ds",
"transaction_status": "succeed",
"transaction_amount": "0.37",
"transaction_currency": "USDT",
"authorization_amount": "0.00",
"authorization_currency": "USDT",
"settlement_amount": "0.37",
"settlement_currency": "USDT",
"fee_amount": "0.00",
"fee_currency": "USDT",
"merchant_data": {"name": "Example Store"},
"transaction_time": "2026-08-24T12:00:02Z",
"updated_time": "2026-08-24T12:00:02Z"
}
}
A failed or unknown deduction does not fabricate a succeed transaction event. The fee remains in the business task for retry or continuation from the failed step, and the transaction event is sent only after recovery succeeds.
14. Endpoint request and response index#
The tables below summarize every endpoint at field level. Follow the API Reference link for the complete schema, constraints, and examples.
14.1 Accounts#
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
GET /payment/account |
No path, query, or body fields | account: current account details, currencies, and timestamps |
Open → |
GET /payment/balances |
Optional currency |
balances[]: total, available, and frozen balances by currency |
Open → |
GET /payment/deposits |
Optional currency, network, status, time range, and pagination | deposits[], total, total_pages |
Open → |
GET /payment/ledger |
Optional currency, record type, time range, pagination, and sorting | entries[], total, total_pages |
Open → |
14.2 Products and files#
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
GET /payment/vcc/products |
Query: limit, offset |
products[]: product code, name, card form, currency, fees, top-up limits, and required customer fields; total |
Open → |
POST /payment/vcc/files |
Multipart: required file; JPG/JPEG, PNG, or PDF; maximum 2 MiB per file |
file_id: platform file identifier |
Open → |
14.3 Customers#
Customer request and response fields include names, gender, email, phone country code, mobile number, date of birth, address, residence country, nationality, postal code, and product-specific additional_customer_data.
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
POST /payment/vcc/customers |
Body: required request_id and customer profile; optional additional_customer_data |
customer: saved profile, customer_id, status, and timestamps |
Open → |
GET /payment/vcc/customers |
Query: limit, offset |
customers[]: customer summaries; total |
Open → |
GET /payment/vcc/customers/{customer_id} |
Path: required customer_id |
customer: profile, status, timestamps, and masked additional data |
Open → |
PATCH /payment/vcc/customers/{customer_id} |
Path: customer_id; body: new request_id and complete customer profile |
customer: updated profile and timestamps |
Open → |
14.4 Card applications#
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
POST /payment/vcc/card-applications |
Body: required request_id, customer_id, product_code |
application: application ID, referenced customer and product, status, creation time |
Open → |
GET /payment/vcc/card-applications |
Query: limit, offset |
applications[]: application records; total |
Open → |
GET /payment/vcc/card-applications/{application_id} |
Path: required application_id |
application: status, next action, amount snapshots, card_id or failure fields, timestamps |
Open → |
14.5 Cards#
Card responses contain card_id, customer_id, product_code, masked card number, last four digits, card status, settlement currency, and timestamps.
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
GET /payment/vcc/cards |
Query: limit, offset |
cards[]: card summaries; total |
Open → |
GET /payment/vcc/cards/{card_id} |
Path: required card_id |
card: current card details and status |
Open → |
GET /payment/vcc/cards/{card_id}/balance |
Path: required card_id |
card_id, available_balance, balance_currency, updated_at |
Open → |
POST /payment/vcc/cards/sensitive |
Body: required card_id; optional Base64 X.509/SPKI public_key override |
encrypt_data: RSA-encrypted, Base64-encoded sensitive-card JSON |
Open → |
14.6 Top-ups, withdrawals, and card status#
Top-up responses contain request and top-up IDs, card ID, status, principal, fee, total debit, settlement currency, failure fields, and timestamps.
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
POST /payment/vcc/cards/{card_id}/topups |
Path: card_id; body: required request_id, positive decimal-string topup_amount |
topup: accepted top-up record and current status |
Open → |
GET /payment/vcc/topups |
Query: limit, offset |
topups[]: top-up records; total |
Open → |
GET /payment/vcc/topups/{topup_id} |
Path: required topup_id |
topup: status, amounts, failure fields, and timestamps |
Open → |
POST /payment/vcc/cards/{card_id}/withdrawals |
Path: card_id; body: required request_id, unique merchant_withdrawal_no, positive decimal-string withdrawal_amount |
withdrawal: accepted withdrawal record and current status |
Open → |
GET /payment/vcc/withdrawals |
Optional merchant_withdrawal_no, card_id, withdrawal_status, limit, and offset filters |
withdrawals and total |
Open → |
GET /payment/vcc/withdrawals/{withdrawal_id} |
Path: withdrawal_id |
withdrawal: current withdrawal record and status |
Open → |
POST /payment/vcc/cards/{card_id}/freeze |
Path: card_id; body: required request_id |
request_id, card_id, resource_status |
Open → |
POST /payment/vcc/cards/{card_id}/unfreeze |
Path: card_id; body: required request_id |
request_id, card_id, resource_status |
Open → |
14.7 Transactions#
Transaction records contain stable identifiers, the four public types and three public statuses, original/authorization/settlement amounts, aggregate fee fields, merchant fields, the original transaction ID, and occurred_at.
| Method and path | Request fields | Response data | API Reference |
|---|---|---|---|
GET /payment/vcc/cards/{card_id}/transactions |
Path: card_id; filters: type, status, start_at, end_at; pagination |
transactions[]: transactions for the card; total |
Open → |
GET /payment/vcc/transactions |
Filters: transaction/card/product IDs, type, status, start_at, end_at; pagination |
transactions[]: VCC transactions; total |
Open → |
POST /payment/vcc/transactions/simulate |
Body: idempotent request_id, card_id, optional original_transaction_id, simulation type, positive amount |
transaction: committed local transaction; Sandbox/local only |
Open → |
15. Error handling#
Branch on the machine-readable code, not on the text in message.
| HTTP | Code | Handling |
|---|---|---|
| 401 | AUTHENTICATION_FAILED |
Check the API Key and environment |
| 403 | PERMISSION_DENIED |
Check the permission required by the endpoint |
| 403 | CARD_TRANSACTION_SIMULATION_DISABLED |
Use the simulation endpoint only in Sandbox/local environments |
| 400 | VALIDATION_ERROR |
Correct the reported field values |
| 409 | IDEMPOTENCY_CONFLICT |
Replay the original parameters or create a new business request |
| 404 | CUSTOMER_NOT_FOUND |
Check customer_id |
| 404 | CARD_APPLICATION_NOT_FOUND |
Check application_id |
| 404 | CARD_NOT_FOUND |
Check card_id |
| 404 | TOPUP_NOT_FOUND |
Check topup_id |
| 404 | ORIGINAL_TRANSACTION_NOT_FOUND |
Check the linked simulated original_transaction_id, account, and card |
| 409 | CARD_WITHDRAWAL_ORDER_CONFLICT |
Reuse the original card and amount or create a new merchant withdrawal number |
| 409 | CARD_OPERATION_IN_PROGRESS |
Wait for the current card-limit operation to finish before submitting another |
| 409 | ORIGINAL_TRANSACTION_INVALID |
Use an original simulated transaction whose type, state, and remaining amount accept the action |
| 409 | CARD_STATUS_NOT_ALLOWED |
Use an active card whose current state allows the operation |
| 422 | CARD_WITHDRAWAL_NOT_SUPPORTED |
Use this operation only with a shared-mode card that supports withdrawal |
| 422 | PRODUCT_UNAVAILABLE |
Query the current products again |
| 422 | TOPUP_AMOUNT_OUT_OF_RANGE |
Use the product’s current top-up limits |
| 422 | INSUFFICIENT_CARD_BALANCE |
Reduce the simulated debit/credit or use a card with sufficient balance/refundable principal |
| 500 | INTERNAL_ERROR |
Reconcile with the original resource ID or request_id before retrying |