Last updated: 2026-08-21
Download Markdown

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_status for card applications.
  • topup_status for top-ups.
  • withdrawal_status for shared-card withdrawals.
  • resource_status in freeze and unfreeze responses and status Webhooks.
  • card_status for 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_id with different parameters returns IDEMPOTENCY_CONFLICT.
  • Save the mapping from request_id to customer_id, application_id, topup_id, withdrawal_id, or the affected card_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#

  1. Verify the HMAC signature against the original body.
  2. Select the payload contract using X-Webhook-Event.
  3. For transaction events, validate event_type, data.transaction_id, and data.card_id; for other events, validate event_type, event_subtype, and account_id.
  4. Insert event_id under a unique constraint.
  5. Return 2xx immediately for an already persisted event ID.
  6. Upsert transaction events by data.transaction_id. For withdrawal events, update resource_status idempotently by withdrawal_id; for other events except 3DS, query the referenced resource for its current state.
  7. Update local state transactionally.
  8. Return 2xx only 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

16. Downloadable contracts#