> ## Documentation Index
> Fetch the complete documentation index at: https://developers.uqpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration FAQ

> Answers to common questions encountered during card issuance API integration, based on real customer feedback.

Common questions and solutions gathered from real integration experiences. If you don't find your answer here, contact your UQPAY account manager.

## Sandbox testing

<Accordion title="Simulation API returns 'Card does not exists'">
  The sandbox simulation endpoint only accepts cards with a specific BIN. The currently supported BIN for simulation is `40963608`. Cards with other BINs will return this error.

  Also check:

  * The card has not been cancelled. Cancelled cards cannot process authorizations.
  * You are using the correct sandbox base URL: `https://api-sandbox.uqpaytech.com/api`
</Accordion>

<Accordion title="Cannot create cards in sandbox: 'insufficient_sub_bin'">
  This means the pre-allocated card pool for your BIN is exhausted. Contact your UQPAY account manager to request additional card allocation for the specific BIN.

  The card count shown in the dashboard reflects only **active** cards, not the total allocated pool. You cannot self-service replenish the pool.
</Accordion>

<Accordion title="Sandbox deposits require manual approval">
  In sandbox, simulated deposits require manual approval by UQPAY staff before the balance is credited. Submit the deposit reference ID in your support group and staff will approve it. This approval step does not exist in production.
</Accordion>

<Accordion title="How do I get physical card numbers for sandbox testing?">
  You cannot use random card numbers for the Assign Card API. UQPAY provisions a set of physical card numbers for sandbox use and sends them to you. Request these from your UQPAY account manager.
</Accordion>

## Authentication and API setup

<Accordion title="Access token validity period">
  Access tokens are valid for **30 minutes**. Cache only one token at a time — generating a new token immediately invalidates all previously issued tokens, regardless of their remaining expiry time.

  Use the `expired_at` field in the token response to determine when to refresh. See [Request Access Token](/account-center/v1.6/api-reference/access-token).
</Accordion>

<Accordion title="Error: 'x-on-behalf-of' validation failed">
  The `x-on-behalf-of` header requires strict validation:

  * Must be a valid UUID format (e.g., `18523f72-f4de-4f9c-bb8e-ec7d1c4f32be`)
  * Must correspond to a valid **Issuing** sub-account ID
  * Empty or malformed values return an error

  If you receive `sub_account_not_found`, verify the account ID belongs to the Issuing business line (not Banking), and that the sub-account is activated.
</Accordion>

<Accordion title="API Key IP whitelist">
  The IP restriction on the API Key is matched against your server's actual outbound IP reaching UQPAY. If you are behind a VPN or proxy, ensure the configured IP matches your real outbound IP. Local/private IPs (e.g., `192.168.x.x`) are not routable and will always fail.
</Accordion>

<Accordion title="How does x-idempotency-key work?">
  Submitting the same `x-idempotency-key` on a repeat request returns the cached result of the original request — no new operation is created. Important behaviors:

  * The cached response persists for **24 hours**
  * If the original request **failed** (e.g., insufficient balance), retrying with the same key returns the same failure — even if conditions have changed. Use a **new** key when retrying after fixing the root cause.
  * If you receive a 504 timeout, retry with the **same** key — the server may have already processed the request
</Accordion>

<Accordion title="'Parse file failed' when uploading KYC documents">
  Two common causes:

  1. **Missing Content-Type**: Always include `Content-Type: multipart/form-data` for file uploads
  2. **Reused idempotency key**: The `x-idempotency-key` must be a valid UUID and unique for each new request
</Accordion>

## Cardholders

<Accordion title="Cardholder name must be in English">
  `first_name` and `last_name` must be in English (Latin characters). Chinese or other non-Latin characters are not accepted. Address fields within `delivery_address` do accept Chinese.
</Accordion>

<Accordion title="Error: 'invalid_phone_number'">
  The phone number must match the `country_code` format. Pass the `country_code` matching the phone number's dialing region, not the cardholder's nationality. Numbers should be in international format without the leading zero.

  See [Phone Number Validation Rules](/card-issuance/v1.6/guide/phone-number-validation-rules-for-cardholder) for details.
</Accordion>

<Accordion title="Can cardholders share the same email or phone number?">
  Uniqueness is enforced **per account**. Within the same `account_id`, email and phone number must each be unique — no two cardholders under that account can share either value. The same email or phone can be reused under a different `account_id`.
</Accordion>

<Accordion title="Can cardholders be deleted?">
  No. There is no Delete Cardholder API. Cardholders cannot be removed once created.
</Accordion>

## Card creation and configuration

<Accordion title="Error: 'risk_control_not_allowed'">
  The `risk_controls` parameter (including `allow_3ds_transactions`) is only supported on specific card products. Passing this parameter for an unsupported product returns an error. The same restriction applies to `no_pin_payment_amount`.

  See [Card products](/card-issuance/v1.6/guide/card-products) for the capability matrix.
</Accordion>

<Accordion title="Error: 'card quota of account exceeds limit'">
  Your account has reached its maximum card creation limit. Contact your UQPAY account manager to increase the quota.
</Accordion>

<Accordion title="Error: 'card bin not config'">
  The BIN or sub-BIN has not been configured for your account. Provide your account ID to UQPAY support and they will assign the appropriate sub-BIN pool. This error also recurs when the sub-BIN pool is exhausted.
</Accordion>

<Accordion title="Card stays in Pending status after creation">
  Cards are created in `PENDING` status and transition to `ACTIVE` once provisioning completes. To detect activation, either listen for the [`card.create.succeeded` webhook](/card-issuance/v1.6/webhooks/card-created) or poll the Retrieve Card endpoint — both are supported.
</Accordion>

<Accordion title="What is the maximum per-transaction spending limit?">
  Each card has a maximum single-transaction spending cap enforced by the platform. The specific cap depends on your account configuration, and higher caps are available via a VIP whitelist on a per-card basis. Contact your UQPAY account manager to confirm or adjust the limit for your account.
</Accordion>

<Accordion title="Sub-account creation limit">
  There is a cap on the number of sub-accounts you can create under a main account. The specific limit depends on your account configuration — contact your UQPAY account manager to confirm or adjust it for your account.
</Accordion>

## Card status and lifecycle

<Accordion title="What are all possible card_status values?">
  | Status       | Description                                                 | Controlled by |
  | ------------ | ----------------------------------------------------------- | ------------- |
  | `ACTIVE`     | Card is active and can process transactions                 | Merchant      |
  | `FROZEN`     | Card is temporarily frozen — can be unfrozen via API        | Merchant      |
  | `BLOCKED`    | Card is blocked by risk controls — requires UQPAY to unlock | System        |
  | `PRE_CANCEL` | Card is scheduled for cancellation (30-day wait)            | —             |
  | `CANCELLED`  | Card is permanently cancelled                               | —             |

  See [Card Lifecycle](/card-issuance/v1.6/guide/card-lifecycle) for the full state transition diagram.
</Accordion>

<Accordion title="What is the difference between FROZEN and BLOCKED?">
  **FROZEN** is merchant-controlled: you can freeze and unfreeze a card via the API without contacting UQPAY.

  **BLOCKED** is system-triggered by risk controls (e.g., consecutive failed PIN or expiry attempts). BLOCKED cards can only be unlocked by UQPAY operations — submit an email to `support@uqpay.com` with the cardholder name, card ID, current status, and reason for unlock.

  Refunds and reversals can still post to both FROZEN and BLOCKED cards.
</Accordion>

<Accordion title="Can I go directly from FROZEN to CANCELLED?">
  Yes. You can transition a card from `FROZEN` directly to `CANCELLED` in a single API call without first reverting to `ACTIVE`.
</Accordion>

<Accordion title="What happens after a card is cancelled?">
  After cancellation is requested, the card enters `PRE_CANCEL` status for a 30-day waiting period, then automatically transitions to `CANCELLED`. During `PRE_CANCEL`:

  * The card cannot process new transactions
  * Previously authorized transactions may still settle
  * For Single cards, UQPAY automatically sweeps remaining balance back to the merchant account after the waiting period
</Accordion>

<Accordion title="Can I change limits on a FROZEN card?">
  No. You must unfreeze the card (set to `ACTIVE`) before assigning or modifying its limit.
</Accordion>

<Accordion title="Virtual vs physical card activation">
  **Virtual cards** are active immediately upon successful creation — no activation step is required. See [Issue Virtual Cards](/card-issuance/v1.6/guide/issue-virtual-cards).

  **Physical cards** require activation via `/api/v1/issuing/cards/activate`, using the activation code delivered by the [`card.activation.code` webhook](/card-issuance/v1.6/webhooks/activation-code) after assignment. See [Issue Physical Cards](/card-issuance/v1.6/guide/issue-physical-cards).
</Accordion>

## Card funding and limits

<Accordion title="Single card vs Share card: limit and funding differences">
  | Behavior        | Single Card                                  | Share Card                          |
  | --------------- | -------------------------------------------- | ----------------------------------- |
  | **Funding**     | Use `recharge` / `withdraw` APIs             | Draws from merchant pool balance    |
  | **card\_limit** | Cannot be changed after creation             | Can be modified via Update Card API |
  | **Fees**        | Deducted from card balance (may go negative) | Deducted from pool account          |

  See [Core Concepts](/card-issuance/v1.6/guide/core-concepts) for background on card types.
</Accordion>

<Accordion title="Error: 'The single card not support changing card limits'">
  Single-mode cards do not support modifying `card_limit` after creation. To adjust a Single card's spendable amount, use the `recharge` and `withdraw` APIs instead.
</Accordion>

<Accordion title="Is there an API to transfer funds from Banking to Issuing?">
  No. Currently there is no API for transferring funds between the Banking and Issuing business lines. This must be done manually via the Dashboard's **Deposit** button in the Issuing section.
</Accordion>

<Accordion title="Error: 'product_not_found' when transferring between accounts">
  This means the Issuing transfer product has not been configured for the sub-account. Contact UQPAY operations to activate it.
</Accordion>

## Transactions and settlement

<Accordion title="What are the possible transaction_status values?">
  | Status     | Description          |
  | ---------- | -------------------- |
  | `APPROVED` | Transaction approved |
  | `DECLINED` | Transaction declined |

  `PENDING` is a transient state that exists only briefly during processing — do not act on it. Wait for the `issuing.transaction.authorization` webhook, which always carries a terminal state. The `REFUNDED` status was removed as of May 29, 2025.
</Accordion>

<Accordion title="The 'failure_reason' field is empty in transaction responses">
  The `failure_reason` field was renamed to `description` as of May 29, 2025. Update your integration to read the `description` field instead.

  This change affects:

  * List Cards Transactions API
  * Retrieve Cards Transaction API
  * `card.transaction.*` webhook events
  * Exported transaction reports
</Accordion>

<Accordion title="How do I distinguish ATM withdrawals from regular purchases?">
  Both ATM withdrawals and regular purchases return `AUTHORIZATION` as the `transaction_type`. To differentiate, check `merchant_data.category_code`:

  * MCC `6011` = ATM cash withdrawal
  * MCC `6011` with `billing_amount == 0` = ATM balance inquiry
  * Other MCC values = regular purchase
</Accordion>

<Accordion title="Error: 'card credit limit greater than max Limit'">
  This means the card's `card_limit` exceeds the platform's maximum allowed single-transaction cap configured for your account. Contact your UQPAY account manager to raise the cap via a VIP whitelist, or keep per-card limits within the configured cap.
</Accordion>

<Accordion title="Error: 'Exceed Pin Free Amount'">
  This decline indicates the transaction exceeded the configured contactless/no-PIN limit for the card. The cardholder should retry with PIN entry.
</Accordion>

<Accordion title="Should I trust a 200 response from recharge/withdraw as confirmation?">
  No. A 200 response only confirms UQPAY received your request. The actual business result is only guaranteed by the **webhook callback**. Always use webhooks as the authoritative source of truth.
</Accordion>

## Webhooks

<Accordion title="Not receiving webhook notifications">
  Check these common causes:

  1. **Event subscription**: Verify you have subscribed to the specific event type. For example, wallet binding OTPs require `card.verification.otp`; transaction validation requires `issuing.transaction.validation`.
  2. **HTTP 200 response**: Your endpoint must return HTTP `200` within the timeout period.
  3. **URL accessibility**: Ensure your webhook URL is publicly accessible from UQPAY's source IPs.

  See [Webhook Delivery Troubleshooting Guide](/account-center/v1.6/guide/webhook-delivery-troubleshooting-guide) for the full checklist.
</Accordion>

<Accordion title="What is the webhook retry schedule?">
  See [Retry logic](/account-center/v1.6/guide/webhooks-overview#retry-logic) for the current retry behavior.
</Accordion>

<Accordion title="What are UQPAY's webhook source IP addresses?">
  See the [IP whitelist section in Webhooks Overview](/account-center/v1.6/guide/webhooks-overview#ip-whitelist) for the current list of source IPs to allowlist on your firewall.
</Accordion>

<Accordion title="Can failed webhooks be resent?">
  Yes. Re-send individual events yourself from the Dashboard using the **Re-Trigger** button. See [Check previous webhooks or re-trigger](/account-center/v1.6/guide/webhooks-setting#check-previous-webhooks-or-re-trigger) for step-by-step instructions.
</Accordion>

## 3D Secure and wallet payments

<Accordion title="Why are 3DS fees charged when allow_3ds_transactions is set to N?">
  Whether 3D Secure is triggered for a transaction is decided on the **acquirer** side at checkout time, not on the issuer side. The issuer-side switch `allow_3ds_transactions` only controls **how** the cardholder authenticates once 3DS has been triggered — specifically, whether a frictionless (no interaction) flow is permitted, or whether a challenge flow with manual OTP entry is required.

  Because the trigger happens at the acquirer, a transaction can still enter the 3DS flow even when `allow_3ds_transactions` is `N`, which is why 3DS verification fees may still be incurred.

  To bypass 3DS entirely (and avoid the associated verification fees), set `enable_3ds` to `N` on the card. This unregisters the card from 3DS so the acquirer cannot trigger 3DS authentication on it. See [3D Secure](/card-issuance/v1.6/guide/3d-secure) for the full two-field model.
</Accordion>

<Accordion title="No OTP webhook received for wallet binding">
  Wallet binding OTPs require subscribing to the `card.verification.otp` event type specifically. Standard `ISSUING` webhook subscriptions do not include this.
</Accordion>

<Accordion title="Can cardholder email notifications be disabled?">
  Yes. UQPAY can disable email sending to cardholders (activation codes, 3DS OTPs) at the account level. You then receive these via webhook and deliver them through your own channel. Contact your account manager to configure.
</Accordion>

## Secure iFrame and PCI

<Accordion title="Retrieve Card Secure requires ACTIVE status">
  The `/cards/:id/secure` endpoint requires the card to be in `ACTIVE` status. Calling it on a `PENDING` card returns `Card does not exists`. Wait for the card to activate first.
</Accordion>

## Physical cards

<Accordion title="Error: 'card has been assigned' on duplicate assign">
  If the card has already been assigned successfully, a second Assign Card call returns this error. The assign operation is not idempotent — use the error response to detect duplicates.
</Accordion>

<Accordion title="Error: 'card number not available for this account'">
  The physical card number being assigned belongs to a batch not allocated to your account. Physical card inventory is account-specific. Verify that the card batch was registered under the correct merchant account.
</Accordion>
