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

# 通过 API 集成虚拟账户

> 选择支持的参数、创建并跟踪申请、使用已激活的银行信息，并对账入账资金。

一笔虚拟账户申请，是针对一个国家和一个币种发起的一次银行信息申请。它可以包含 `LOCAL`、`SWIFT` 或两种收款方式的结果。

> [!NOTE]
>
> 如果已有虚拟账户集成，请先阅读[升级虚拟账户 API 集成](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/guide/migrate-to-virtual-account-applications.md)。

```mermaid theme={null}
flowchart LR
    A["创建申请"] --> B["保存 application_id"]
    B --> C["接收 Webhook 或查询最新详情"]
    C --> D{"是否已有 ACTIVE 银行信息？"}
    D -- "否" --> C
    D -- "是" --> E["展示付款指引"]
    E --> F["对账入账资金"]
```

> [!WARNING]
>
> Create 返回 HTTP `200` 表示申请已受理并进入处理，不表示银行信息已经可用。只能使用状态为 `ACTIVE` 的银行信息。

## 开始前

* 完成入驻，并为目标账户启用 Global Account。
* 配置[虚拟账户申请 Webhook](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/webhooks/virtual-account-create-update.md)。
* 如果操作子账户，请在 Create、List 和 Retrieve 的 `x-on-behalf-of` 中传入其账户 ID。
* 为每笔新申请生成唯一的 `x-idempotency-key`。

## 选择申请参数

选择国家和币种，查看支持的收款方式。生成的 JSON 可用于 [Create Virtual Account](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/api-reference/create-virtual-account.md)。

**国家**

**币种**

**支付方式**

请求参数

<pre aria-live="polite" />

> [accordion] 机器可读的参数组合
>
> 以下列表包含传入 `payment_method` 时支持的全部组合。省略 `payment_method` 时，UQPAY 会针对所选国家和币种分别评估 `LOCAL` 和 `SWIFT`。
>
> ```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" }
> ]
> ```

只申请一种收款方式时，传 `LOCAL` 或 `SWIFT`。如需评估两种方式，可以省略 `payment_method`，或传 `null`、空字符串、仅空白字符。不要传 `ALL` 或 `AUTO`。

## 创建申请

使用一个 `country` 和一个 `currency` 调用 [Create Virtual Account](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/api-reference/create-virtual-account.md)。

UQPAY 会去除 `country`、`currency` 和 `payment_method` 首尾的空格，并接受小写值。`nickname` 省略、为 `null`、为空或仅包含空白字符时按相同方式处理。未定义的 JSON 字段会被忽略。

仅在为同一账户重试相同请求时复用 `x-idempotency-key`。相同请求重试成功时会返回原申请；使用同一 key 提交不同的申请输入会返回 `parameter_conflict`。

收到 HTTP `200` 后：

1. 将 `account_id` 和 `direct_id` 与申请一起保存，以保留其账户层级。
2. 保存 `application_id` 和 `public_version`。
3. 逐项处理 `results[]`，并通过 `payment_method` 识别。
4. 继续跟踪状态为 `SUBMITTED` 的结果。
5. 在具体银行信息变为 `ACTIVE` 前，不要展示付款指引。

评估两种方式时，`LOCAL` 排在 `SWIFT` 之前，但代码不得依赖数组位置。一种方式可能为 `SKIPPED`，另一种为 `SUBMITTED`。

同步 `400` 表示没有创建申请，不要等待申请 Webhook。所有评估方式都不可用时，Create 会返回一个顶层错误，不会创建只有跳过结果的申请。

## 跟踪申请

两个查询接口用途不同：

* [List Virtual Account Applications](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/api-reference/list-virtual-account-applications.md) 用于查找申请摘要。结果按从新到旧排列；可选的 `status`、`country` 和 `currency` 筛选条件会同时生效。结果为空或页码超出范围时，返回 HTTP `200` 和 `data: []`。
* [Retrieve Virtual Account Application](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/api-reference/retrieve-virtual-account-application.md) 用于查询一笔申请的最新完整详情。申请不存在和申请属于其他账户时，均返回相同的 HTTP `400` 错误。

两个接口都会返回 `account_id` 和 `direct_id`。请使用它们将每笔申请关联到正确的账户层级。

使用[虚拟账户申请 Webhook](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/webhooks/virtual-account-create-update.md)接收异步变化。如果投递缺失或疑似乱序，请调用 Retrieve，并为同一个 `application_id` 保留最高的 `public_version`。

### 区分三层状态

| 层级 | 需要回答的问题 | 必须执行的操作 |
| - | - | - |
| 申请 `status` | 整笔申请进展到哪里？ | 用于跟踪进度，然后检查每项结果。 |
| `results[].status` | 这项收款方式处理得怎样？ | 分别处理 `LOCAL` 或 `SWIFT` 结果。 |
| `virtual_accounts[].status` | 这条银行信息现在能否使用？ | 只使用 `ACTIVE`；停止使用 `CLOSED`。 |

| 结果状态 | 处理方式 |
| - | - |
| `SUBMITTED` | 继续等待 Webhook，或查询最新申请详情。 |
| `SKIPPED` | 读取 `error.code`，并继续处理其他结果。 |
| `COMPLETED` | 只使用状态为 `ACTIVE` 的银行信息。 |
| `FAILED` | 读取 `error.code`，并继续接受更高 `public_version` 的后续事件。 |
| `CLOSED` | 停止将相关银行信息用于新的付款指引。 |

| 申请状态 | 含义 |
| - | - |
| `SUBMITTED` | 尚无收款方式完成，且至少一种方式仍在处理中。 |
| `PARTIALLY_COMPLETED` | 至少一种方式已完成，另有方式仍在处理或已失败。 |
| `COMPLETED` | 所有已受理的方式均已完成。 |
| `FAILED` | 没有方式完成，且没有已受理的方式仍在处理中。 |
| `CLOSED` | 所有已开通虚拟账户均已关闭，且没有方式仍在处理中。 |

## 处理错误

接口参数校验和业务错误包含 `type`、`code` 和 `message`。程序处理应使用 `code`。在接口处理请求前返回的鉴权等错误，可能使用网关公共错误格式。

| 接口错误码 | 触发条件 | 处理方式 |
| - | - | - |
| `invalid_parameter` | body、path 或 query 参数无效。 | 修正请求后再试。 |
| `key_invalid` | 缺少 `x-idempotency-key`，或长度超过 64 个字符。 | 传入有效的 key。 |
| `parameter_conflict` | 同一幂等 key 被用于不同的申请输入。 | 保持原请求不变后重试，或为新申请使用新 key。 |
| `virtual_account_product_not_available` | 当前账户未启用虚拟账户。 | 联系 UQPAY 代表。 |
| `account_not_active` | 当前账户未激活。 | 完成账户激活后再申请。 |
| `virtual_account_currency_not_supported` | 当前账户不支持所请求的币种。 | 选择可用币种。 |
| `virtual_account_already_applied` | 所请求方式下的可用选项均已申请。 | 使用已有银行信息，或选择其他受支持方式。 |
| `virtual_account_payment_method_not_supported` | 所请求方式不支持该国家与币种组合。 | 选择受支持的组合。 |
| `virtual_account_no_eligible_channel` | 当前没有可用的虚拟账户选项。 | 重试前联系 UQPAY 代表。 |
| `virtual_account_application_not_accepted` | 省略 `payment_method` 后，评估的方式因不同原因被拒绝。 | 检查账户资格及所请求的国家和币种。 |
| `virtual_account_application_not_found` | 申请不存在或属于其他账户。 | 检查 `application_id` 和当前认证的账户。 |

收款方式被跳过或失败时，`results[].error` 包含 code 和 message；没有错误时为 `null`。

| 结果错误码 | 含义 | 处理方式 |
| - | - | - |
| `VA_ALREADY_APPLIED` | 该方式下可用的虚拟账户选项已申请。 | 通过 List Virtual Accounts 使用已有银行信息。 |
| `VA_METHOD_NOT_SUPPORTED` | 该国家与币种不支持这种收款方式。 | 继续处理其他结果，或选择其他受支持组合。 |
| `VA_NO_ELIGIBLE_CHANNEL` | 该方式当前没有可用的虚拟账户选项。 | 继续处理其他结果，并在重试前联系 UQPAY 代表。 |
| `VA_APPLICATION_REJECTED` | 已受理的收款方式随后被拒绝。 | 不要使用该结果；如需协助解决，请联系 UQPAY 代表。 |
| `VA_PROVISIONING_FAILED` | 开户处理结束，但没有可用银行信息。 | 不要使用该结果；继续接受更高版本，并在需要时联系 UQPAY 代表。 |

## 使用已开通的银行信息

结果变为 `COMPLETED` 后，逐项处理 `virtual_accounts[]`：

* 只使用 `status` 为 `ACTIVE` 的记录。
* 将 `account_bank_id` 视为不透明字符串，并按原值保存，用于关联同一记录的后续变化。
* 按返回值原样展示 `account_holder`、`account_number`、`bank_name`、`bank_address`、`country_code` 和 `currency`。
* 成对保存 `clearing_system.type` 和 `clearing_system.value`，并保留原值。
* 记录变为 `CLOSED` 后立即停止使用。

`close_reason` 始终存在。记录未关闭时为 `""`；记录关闭后，如系统已记录原因则返回该值，否则仍为 `""`。不要等待该字段变为非空才停止使用。

服务启动或进行对账时，可使用 [List Virtual Accounts](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/api-reference/list-virtual-accounts.md) 刷新已开通的银行信息。该既有接口列出银行信息，不列出申请。

## 对账入账资金

虚拟账户用于提供付款指引。[充值](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/guide/deposit.md) 是资金到账后创建的交易记录。

1. 银行信息激活后，保存虚拟账户与所属账户的映射。
2. 监听[充值状态](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/webhooks/deposit-pending-rejected-completed.md)事件。
3. 如果是子账户充值，请使用 Webhook 中的 `account_id` 作为 `x-on-behalf-of` 查询充值详情。
4. 调用 [Retrieve Deposit](https://developers-sandbox.uqpaytech.com/docs/zh/global-account/v1.6/api-reference/retrieve-deposit.md)。
5. 使用 `receiver_account_number`、`currency` 和所属 `account_id` 匹配充值记录；付款人信息和 `deposit_reference` 可在有值时作为辅助信号。


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