> ## 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 Global Acquiring 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.

## Authentication and API Keys

<Accordion title="How do I get my API key and merchant credentials?">
  See [Create API Keys](/account-center/v1.6/guide/create-api-keys) for the step-by-step flow. Your Client ID and API Key are both generated from the Dashboard's **Developer → API Keys** page. The API Key is displayed only once — copy it immediately.
</Accordion>

<Accordion title="I get `unauthorized_error: invalid auth token format` when calling the API. What's wrong?">
  The `x-auth-token` header value must be prefixed with `Bearer ` followed by a space. For example:

  ```
  x-auth-token: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
  ```

  Omitting `Bearer ` or the space after it causes this error. The token itself comes from the [Request Access Token](/account-center/v1.6/api-reference/access-token) endpoint.
</Accordion>

<Accordion title="My token stops working after I generate a new one. Is that expected?">
  Yes. For acquiring, only one token can be active at a time. When you generate a new token, the previous token is immediately invalidated — even if it has not yet expired.

  If you have concurrent requests that may still be using the old token when you rotate, coordinate your refresh logic so in-flight requests complete before you issue a new token. Token expiry is indicated by the `expired_at` field in the token response; the default TTL is 30 minutes. See [Request Access Token](/account-center/v1.6/api-reference/access-token).
</Accordion>

<Accordion title="What is `x-idempotency-key` and when should I send it?">
  See [Idempotent Requests](/account-center/v1.6/guide/idempotent-requests) for the full rules — including the 24-hour key lifecycle and retry behavior. Use a fresh UUID for each new operation; reuse the same key only when retrying the same logical request.
</Accordion>

<Accordion title="I get `Invalid client id` (HTTP 400) when requesting an access token in production. What should I check?">
  This means the `x-client-id` you are using does not exist or does not match the production environment. Verify that you are using the client ID generated from your **production** account at [https://app.uqpay.com](https://app.uqpay.com), not from the sandbox portal at [https://app-sandbox.uqpaytech.com](https://app-sandbox.uqpaytech.com). The two environments use separate credentials.
</Accordion>

***

## Sandbox Testing

<Accordion title="Do I need to go through real KYC in the sandbox?">
  No. Sandbox KYC is mocked — you can submit any values and they will be approved automatically. The sandbox environment is available at [https://app-sandbox.uqpaytech.com](https://app-sandbox.uqpaytech.com). API requests go to `https://api-sandbox.uqpaytech.com`.
</Accordion>

<Accordion title="Does the sandbox validate card numbers and CVCs?">
  No. In the sandbox, card validation is skipped. You can enter any card number and CVC and the transaction will proceed. Use the test cards listed in the [sandbox testing guide](/global-acquiring/v1.6/guide/testing-in-sandbox) to trigger specific scenarios such as 3DS challenge mode, frictionless mode, or failure.
</Accordion>

<Accordion title="Does `merchant_order_id` need to be unique? Can I reuse it?">
  `merchant_order_id` is not validated for uniqueness by UQPAY — you can submit the same value and multiple PaymentIntents will be created. Use `payment_intent_id` (the `PI...` prefix ID returned by our API) as the authoritative order reference within UQPAY.

  **Recommendation:** Assign a unique `merchant_order_id` to every order on your side. This simplifies reconciliation and avoids issues with upstream channels that enforce uniqueness — for example, Alipay CN requires a unique `merchant_order_id`, and submitting duplicates will cause Alipay-side errors.
</Accordion>

***

## Payment Lifecycle and Status

<Accordion title="What are the PaymentIntent (PI) and PaymentAttempt (PA) statuses, and which indicate a successful payment?">
  See [Core Concepts](/global-acquiring/v1.6/guide/core-concepts) for the complete PI and PA status tables, including which status signals success, which triggers each webhook event, and the PI auto-close behavior after 30 minutes.
</Accordion>

<Accordion title="How do I determine whether to judge payment success from PI or PA status?">
  For the common case of one PI to one PA, you can treat PI `SUCCEEDED` as authoritative for payment success. However, because a failed PA causes the PI to revert to `REQUIRES_PAYMENT_METHOD` rather than immediately `FAILED`, you should also monitor PA status to detect failure promptly.

  Recommended approach: subscribe to both `acquiring.payment_attempt.succeeded` (or `acquiring.payment_intent.succeeded`) and `acquiring.payment_attempt.failed` webhooks, and also use `acquiring.cancel.succeeded` for explicit cancellations.
</Accordion>

<Accordion title="How long does a PaymentIntent remain open before it auto-closes?">
  30 minutes. See [Core Concepts — Payment Intent](/global-acquiring/v1.6/guide/core-concepts) for the full expiration behavior.
</Accordion>

<Accordion title="What is the difference between cancellation and refund?">
  * **Cancellation** applies to payments that have not yet reached a final state — see [Cancellation](/global-acquiring/v1.6/guide/cancellation) for eligibility rules per payment method.
  * **Refund** applies to completed payments — see [Refunds](/global-acquiring/v1.6/guide/refunds) for eligibility, refundable amount, and fee handling.
</Accordion>

<Accordion title="After successfully capturing a card payment, can I still cancel it?">
  No. For **card payments**, once a PaymentIntent has been captured and reaches a terminal state (`SUCCEEDED`), cancellation is not available. You must use the refund API if the original capture has been completed. See [Cancellation](/global-acquiring/v1.6/guide/cancellation) for which payment methods support cancellation after success.
</Accordion>

***

## 3D Secure Integration

<Accordion title="How do I control whether 3DS is triggered, and what fields do I need to send?">
  See [3DS Integration Guide — Option 1](/global-acquiring/v1.6/guide/3ds-integration-guide-option-1) and [Option 2](/global-acquiring/v1.6/guide/3ds-integration-guide-option-2) for the full request parameters (including `three_ds_action`, `browser_info`, `ip_address`) and response handling (`next_action.redirect_iframe` vs `next_action.redirect_to_url`).
</Accordion>

<Accordion title="After 3DS completes, the user is not redirected back to my `return_url`. What happened?">
  Check these:

  1. **return\_url not set:** For 3DS, use the `three_ds.return_url` field (not the top-level `return_url`). After a successful 3DS authentication and payment, the user will be redirected to this URL.
  2. **Query parameters truncated:** If your `return_url` contains query parameters, verify they are URL-encoded correctly and not stripped. This was a known issue that has been fixed — if you still see truncation, contact support.
  3. **Both success and failure redirect:** Previously, only successful payments redirected to `return_url`; failures went to a UQPAY error page. This has been updated — both outcomes now redirect to `return_url`. Your results page should query the order status via API rather than relying on the redirect itself as confirmation of success.
</Accordion>

<Accordion title="I'm getting `device_id is invalid` errors for web payments. Can I skip the device ID?">
  When making payments from a web browser, `device_id` is often unavailable. The field is not required for web-context requests. You can omit it for browser-based integrations. Passing a fabricated device ID does not help and may increase rejection rates.
</Accordion>

***

## Webhooks

<Accordion title="How do I set up a webhook endpoint?">
  See [Webhook Settings](/account-center/v1.6/guide/webhooks-setting) for the step-by-step flow. Use separate webhook subscriptions per product line (acquiring, issuing, etc.) to keep event filters clean.
</Accordion>

<Accordion title="I configured a webhook URL but I'm not receiving events. What should I check?">
  1. **IP whitelist:** If your server restricts inbound connections by IP, allowlist UQPAY's webhook source IPs — see the [IP whitelist section in Webhooks Overview](/account-center/v1.6/guide/webhooks-overview#ip-whitelist).
  2. **Subscription scope:** Confirm that you subscribed to the correct event types in the portal.
  3. **Multiple environments:** If both your staging and production systems connect to the UQPAY production environment, you can configure multiple webhook URLs in the same subscription. Be aware that both URLs will receive all events — make sure your systems handle this correctly (e.g., avoid duplicate database writes).

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

***

## Refunds

<Accordion title="I tried to refund an order and got `Insufficient balance`. Why?">
  Refunds are debited from your available balance:

  * **Already-settled orders:** Refunds are deducted from your `Available to pay out` balance.
  * **Not-yet-settled orders:** Refunds are deducted from your `Available soon` (pending) balance.

  If you have withdrawn all of your available balance and no pending settlements have arrived yet, you will not have enough funds to process the refund until the next settlement batch runs.
</Accordion>

<Accordion title="When can I issue a refund in the sandbox?">
  Sandbox refunds require the order to be in `SUCCEEDED` status. Sandbox orders do not auto-settle, so you may encounter `Invalid order status` if you try to refund before the order reaches the correct state. Ask support to manually trigger settlement if you need to test the full refund flow in sandbox.

  If you get `Refund is processing, please try again after`, it means another refund request for the same order is already in progress. Wait for it to complete before submitting a new one.

  See [Refunds](/global-acquiring/v1.6/guide/refunds) and [Testing in Sandbox](/global-acquiring/v1.6/guide/testing-in-sandbox).
</Accordion>

<Accordion title="The refund succeeded on my end but was rejected by the issuer. What can I do?">
  Some issuers (typically the cardholder's bank) will reject refund requests. This is indicated by a `FAILED` status on the refund after it was initially `PROCESSING` or `INITIATED`. Common reasons include the issuer's internal fraud or compliance rules — these are not related to your integration parameters.

  If refunds are failing intermittently rather than consistently, the cause is likely the issuer side rather than a configuration issue. UQPAY will raise a ticket with the card network on your behalf, but final resolution depends on the issuer.
</Accordion>

***

## Settlement and Reconciliation

<Accordion title="Where do I find settlement reports?">
  See [Settlement Report](/global-acquiring/v1.6/guide/settlement-report) for the downloadable CSV formats (Payment Report and Settlement Report) and a full field-by-field description of each column.
</Accordion>

***

## POS Integration

<Accordion title="Where do I find the POS API documentation?">
  * [POS API Integration Guide](/global-acquiring/v1.6/guide/pos-integration)
  * [Register Terminal API](/global-acquiring/v1.6/api-reference/register-terminal)
  * [Get PIN Key API](/global-acquiring/v1.6/api-reference/get-pin-key)
  * [Create PaymentIntent API](/global-acquiring/v1.6/api-reference/create-payment-intent)
</Accordion>
