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

# Integrate Virtual Accounts with the API

> Choose a supported request, create and track an application, use active bank details, and reconcile incoming funds.

A Virtual Account application is one request for bank details in one country and one currency. It can contain a `LOCAL` result, a `SWIFT` result, or both.

> [!NOTE]
>
> Updating an existing integration? Start with [Upgrade Your Virtual Account Integration](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/guide/migrate-to-virtual-account-applications.md).

```mermaid theme={null}
flowchart LR
    A["Create application"] --> B["Store application_id"]
    B --> C["Receive webhook or retrieve latest details"]
    C --> D{"ACTIVE bank details available?"}
    D -- "No" --> C
    D -- "Yes" --> E["Show payment instructions"]
    E --> F["Reconcile deposits"]
```

> [!WARNING]
>
> HTTP `200` from Create means the application was accepted for processing. It does not mean bank details are ready. Use only bank-detail records whose status is `ACTIVE`.

## Before you start

* Complete onboarding and enable Global Account for the target account.
* Configure the [Virtual Account Application Webhooks](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/webhooks/virtual-account-create-update.md).
* For a connected account, send its account ID in `x-on-behalf-of` on Create, List, and Retrieve.
* Generate a unique `x-idempotency-key` for each new application.

## Choose what to request

Select a country and currency to see the supported payment methods. The generated JSON can be used in [Create Virtual Account](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/api-reference/create-virtual-account.md).

**Country**

**Currency**

**Payment method**

Request parameters

<pre aria-live="polite" />

> [accordion] Machine-readable combinations
>
> The following list contains every supported combination when `payment_method` is provided. If you omit `payment_method`, UQPAY evaluates `LOCAL` and `SWIFT` separately for the selected country and currency.
>
> ```json theme={null}
> [
>   { "country": "AU", "currency": "AUD", "payment_method": "LOCAL" },
>   { "country": "BH", "currency": "EUR", "payment_method": "SWIFT" },
>   { "country": "BH", "currency": "GBP", "payment_method": "SWIFT" },
>   { "country": "BH", "currency": "USD", "payment_method": "SWIFT" },
>   { "country": "DE", "currency": "EUR", "payment_method": "LOCAL" },
>   { "country": "DE", "currency": "EUR", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "EUR", "payment_method": "LOCAL" },
>   { "country": "DK", "currency": "GBP", "payment_method": "LOCAL" },
>   { "country": "DK", "currency": "AUD", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "CHF", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "CNH", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "EUR", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "GBP", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "HKD", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "JPY", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "NZD", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "SGD", "payment_method": "SWIFT" },
>   { "country": "DK", "currency": "USD", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "EUR", "payment_method": "LOCAL" },
>   { "country": "GB", "currency": "GBP", "payment_method": "LOCAL" },
>   { "country": "GB", "currency": "AED", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "AUD", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "CAD", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "CNH", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "EUR", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "GBP", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "HKD", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "JPY", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "KWD", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "MXN", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "SGD", "payment_method": "SWIFT" },
>   { "country": "GB", "currency": "USD", "payment_method": "SWIFT" },
>   { "country": "LU", "currency": "EUR", "payment_method": "LOCAL" },
>   { "country": "LU", "currency": "EUR", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "SGD", "payment_method": "LOCAL" },
>   { "country": "SG", "currency": "AED", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "AUD", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "CNH", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "EUR", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "GBP", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "HKD", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "JPY", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "NOK", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "SGD", "payment_method": "SWIFT" },
>   { "country": "SG", "currency": "USD", "payment_method": "SWIFT" }
> ]
> ```

Send `LOCAL` or `SWIFT` when you need one receiving method. Omit `payment_method`, or send `null`, an empty string, or whitespace, to evaluate both. Do not send `ALL` or `AUTO`.

## Create an application

Call [Create Virtual Account](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/api-reference/create-virtual-account.md) with one `country` and one `currency`.

UQPAY removes surrounding whitespace and accepts lowercase values for `country`, `currency`, and `payment_method`. Omitted, `null`, empty, and whitespace-only `nickname` values are treated the same. Undocumented JSON fields are ignored.

Use the same `x-idempotency-key` only when retrying the same request for the same account. A successful identical retry returns the original application. Reusing the key with different application input returns `parameter_conflict`.

After HTTP `200`:

1. Store `account_id` and `direct_id` with the application so you can preserve its account hierarchy.
2. Store `application_id` and `public_version`.
3. Process every entry in `results[]` and identify it by `payment_method`.
4. Continue tracking any `SUBMITTED` result.
5. Do not show payment instructions until an individual bank-detail record is `ACTIVE`.

When both methods are evaluated, `LOCAL` appears before `SWIFT`, but your code must not depend on array position. One method can be `SKIPPED` while the other is `SUBMITTED`.

A synchronous `400` means the application was not created. Do not wait for an application webhook. If every evaluated method is unavailable, Create returns one top-level error rather than an application containing only skipped results.

## Track the application

Use both queries for different tasks:

* [List Virtual Account Applications](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/api-reference/list-virtual-account-applications.md) finds application summaries. Results are newest first. Optional `status`, `country`, and `currency` filters are combined. An empty or out-of-range page returns HTTP `200` with `data: []`.
* [Retrieve Virtual Account Application](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/api-reference/retrieve-virtual-account-application.md) returns the latest full details for one application. A missing application and an application owned by another account return the same HTTP `400` error.

Both responses include `account_id` and `direct_id`. Use them to associate each application with the correct account hierarchy.

Use [Virtual Account Application Webhooks](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/webhooks/virtual-account-create-update.md) for asynchronous changes. If a delivery is missing or appears out of order, call Retrieve and keep the highest `public_version` for that `application_id`.

### Read the three status levels

| Level | Customer question | Required action |
| - | - | - |
| Application `status` | What is the overall progress? | Use it for tracking, then inspect every result. |
| `results[].status` | What happened to this receiving method? | Process each `LOCAL` or `SWIFT` result independently. |
| `virtual_accounts[].status` | Can this bank detail be used now? | Use only `ACTIVE`; stop using `CLOSED`. |

| Result status | What to do |
| - | - |
| `SUBMITTED` | Continue waiting for a webhook or retrieve the latest application. |
| `SKIPPED` | Read `error.code` and continue processing other results. |
| `COMPLETED` | Use only bank details whose status is `ACTIVE`. |
| `FAILED` | Read `error.code`. Still accept a later event with a higher `public_version`. |
| `CLOSED` | Stop presenting the related bank details for new payments. |

| Application status | Meaning |
| - | - |
| `SUBMITTED` | No method has completed and at least one method is still processing. |
| `PARTIALLY_COMPLETED` | At least one method completed while another is processing or failed. |
| `COMPLETED` | Every accepted method completed. |
| `FAILED` | No method completed and no accepted method remains in progress. |
| `CLOSED` | All issued Virtual Accounts are closed and no method remains in progress. |

## Handle errors

API validation and business errors contain `type`, `code`, and `message`. Use `code` for programmatic handling. Authentication and other errors returned before the endpoint processes the request can use the common gateway error format.

| API error code | When it occurs | What to do |
| - | - | - |
| `invalid_parameter` | A body, path, or query value is invalid. | Correct the request before retrying. |
| `key_invalid` | `x-idempotency-key` is missing or exceeds 64 characters. | Send a valid key. |
| `parameter_conflict` | The same idempotency key is reused with different application input. | Retry the original request unchanged, or use a new key for a new application. |
| `virtual_account_product_not_available` | Virtual Accounts are not enabled for the account. | Contact your UQPAY representative. |
| `account_not_active` | The account is not active. | Complete account activation before applying. |
| `virtual_account_currency_not_supported` | The requested currency is unavailable for the account. | Choose an available currency. |
| `virtual_account_already_applied` | All available options for the requested method were already applied. | Use existing issued bank details or choose another supported method. |
| `virtual_account_payment_method_not_supported` | The requested method is unsupported for the country and currency. | Choose a supported combination. |
| `virtual_account_no_eligible_channel` | No Virtual Account option is currently available. | Contact your UQPAY representative before retrying. |
| `virtual_account_application_not_accepted` | Methods evaluated from an omitted `payment_method` were rejected for different reasons. | Review account eligibility and the requested country and currency. |
| `virtual_account_application_not_found` | The application does not exist or belongs to another account. | Check `application_id` and the authenticated account context. |

When a receiving method is skipped or fails, `results[].error` contains a code and message. It is `null` when no error applies.

| Result error code | Meaning | What to do |
| - | - | - |
| `VA_ALREADY_APPLIED` | The available Virtual Account option for this method was already applied. | Use existing bank details from List Virtual Accounts. |
| `VA_METHOD_NOT_SUPPORTED` | This method is unsupported for the requested country and currency. | Continue with other results or choose another supported combination. |
| `VA_NO_ELIGIBLE_CHANNEL` | No Virtual Account option is currently available for this method. | Continue with other results and contact your UQPAY representative before retrying. |
| `VA_APPLICATION_REJECTED` | The accepted method was later rejected. | Do not use this result. Contact your UQPAY representative if you need help resolving the rejection. |
| `VA_PROVISIONING_FAILED` | Account setup ended without usable bank details. | Do not use this result. Continue to accept a later higher version and contact your UQPAY representative if needed. |

## Use issued bank details

When a result becomes `COMPLETED`, process every entry in `virtual_accounts[]`:

* Use only records whose `status` is `ACTIVE`.
* Treat `account_bank_id` as an opaque string. Store it as returned to correlate later changes to the same record.
* Show `account_holder`, `account_number`, `bank_name`, `bank_address`, `country_code`, and `currency` exactly as returned.
* Store `clearing_system.type` and `clearing_system.value` together and preserve both values.
* Stop using a record as soon as its status is `CLOSED`.

`close_reason` is always present. It is `""` for a non-closed record. For a closed record, it contains a reason when one was recorded and otherwise remains `""`. Never wait for a non-empty value before stopping use.

Use [List Virtual Accounts](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/api-reference/list-virtual-accounts.md) during startup or reconciliation to refresh issued bank details. This existing endpoint lists bank details, not applications.

## Reconcile incoming funds

A Virtual Account provides payment instructions. A [Deposit](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/guide/deposit.md) is the transaction created when funds arrive.

1. Store the Virtual Account and owning account mapping when bank details become active.
2. Listen for [Deposit Status](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/webhooks/deposit-pending-rejected-completed.md) events.
3. For a connected account, use the webhook `account_id` as `x-on-behalf-of` when retrieving the deposit.
4. Call [Retrieve Deposit](https://developers-sandbox.uqpaytech.com/docs/global-account/v1.6/api-reference/retrieve-deposit.md).
5. Match the deposit using `receiver_account_number`, `currency`, and the owning `account_id`. Use sender details and `deposit_reference` as additional signals when available.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.