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

# 使用虚拟账户收取本地付款

> 为每个付款人提供专属的本地银行信息，将其付款入账到商户的法币余额，并通过 depositAlias 将每笔充值与付款人匹配。

使用此流程从您自己的客户处收取本地货币付款（MXN、ARS、COP、BRL），并入账到商户的法币余额（也称为待处理资金 / Pending Fund 余额）。您为每个付款人提供一个拥有专属银行信息的虚拟账户，付款人发起本地转账后，VelaFi 会为商户余额入账，并向您发送一条 `FUNDING_WEBHOOK`，其中注明资金到账的虚拟账户。您可以从该余额[出金](https://docs.velafi.com/cn/docs/use-cases/payouts-from-balance.md)、将资金划转给另一个商户，或购买加密货币。

## 工作原理

```mermaid theme={null}
sequenceDiagram
    participant You as 您的平台
    participant V as VelaFi
    participant P as 付款人
    You->>V: POST /v2/merchant/virtual/accounts (alias = 付款人 ID)
    You->>V: GET /v2/merchant/virtual/addfunds (depositAlias)
    V-->>You: 该别名的银行信息 (fieldList)
    You->>P: 展示银行信息
    P->>V: 本地转账 (SPEI, CVU, Pix, Bre-B...)
    V->>V: 为商户法币余额入账
    V->>You: FUNDING_WEBHOOK (type DEPOSIT, status 2, depositAlias)
    You-->>V: HTTP 200 {"callbackStatus":"SUCCESS"}
    You->>V: GET /v2/merchant/funding/records (对账)
```

### 一个账户还是每个付款人一个账户

| 方案 | 如何获取收款信息 | 如何知道谁付了款 | 适用场景 |
| - | - | - | - |
| 商户币种账户 | [`GET /v2/merchant/addfunds`](https://docs.velafi.com/cn/api-reference/merchant/get-pending-fund-account) | Webhook 中的付款人字段（`payerName`、`payerAccount`、`taxId`），具体取决于支付通道 | 您为自己的余额注资，或付款人数量很少 |
| 每个付款人一个虚拟账户 | [`POST /v2/merchant/virtual/accounts`](https://docs.velafi.com/cn/api-reference/merchant/create-multiple-virtual-account)，然后 [`GET /v2/merchant/virtual/addfunds`](https://docs.velafi.com/cn/api-reference/merchant/get-multiple-virtual-account) | Webhook 和资金记录中的 `depositAlias` | 您向大量客户收款，并需要将每笔付款归属到具体付款人 |

> [!NOTE]
>
> 虚拟账户仅用于归属识别，它没有自己的余额：任何虚拟账户上的每笔充值，都会入账到商户币种账户的唯一余额中。请在您自己的账本中以 `depositAlias` 为键维护每个付款人的余额。

## 开始之前

* **API 访问权限。** 一个 API 密钥、已加入白名单的服务器 IP，以及放在 `X-BH-TOKEN` 请求头中的业务令牌。参见[认证](https://docs.velafi.com/cn/api-reference/authentication.md)。
* **一个已验证的商户。** 参见[创建商户](https://docs.velafi.com/cn/docs/guides/creating-merchant.md)。
* **一个已激活的币种账户**，对应您要收款的币种和渠道（在[获取商户账户列表](https://docs.velafi.com/cn/api-reference/merchant/get-a-list-of-merchant-accounts.md)中状态为 `2`）。参见[激活商户账户](https://docs.velafi.com/cn/docs/guides/activating-merchant-account.md)。
* **一个 `FUNDING_WEBHOOK` 端点**，已注册并能返回所要求的确认响应。参见 [Webhook](https://docs.velafi.com/cn/docs/guides/webhooks.md) 和 [Webhook 设置](https://docs.velafi.com/cn/api-reference/webhooks/webhook-setup.md)。

### 支持虚拟账户的渠道

| 币种 | `paymentId` | 渠道 | 别名规则 |
| - | - | - | - |
| MXN | `105` | SPEI (Finco Pay) | 字母和数字，最多 64 个字符 |
| MXN | `72` | SPEI (Tesored) | 字母和数字，最多 64 个字符 |
| ARS | `63` | CBU/CVU (Momentum) | 字母和数字，最多 64 个字符 |
| COP | `68` | 自动 ACH（付款链接） | 6 到 21 位大写字母或数字 |
| COP | `69` | Bre-B | 6 到 21 位大写字母或数字 |
| BRL | `90` | Pix (Genial) | 字母和数字，最多 64 个字符 |
| BRL | `92` | Pix - Woovi (Avenia) | 字母和数字，最多 64 个字符 |

商户必须已在该渠道拥有已激活的币种账户。如果币种账户所在渠道不支持虚拟账户，将返回 `-5084`（该币种不支持多个虚拟账户）。`default`（不区分大小写）为保留值。

## 分步操作

**1. 为每个付款人创建虚拟账户**

调用 [`POST /v2/merchant/virtual/accounts`](https://docs.velafi.com/cn/api-reference/merchant/create-multiple-virtual-account)，传入商户、币种、渠道以及您自定义的 `alias`。请使用您系统中的稳定 ID（例如客户 ID），这样无需查找表即可匹配充值。别名一经创建便不可更改。

```bash cURL theme={null}
curl -X POST https://api.velafi.com/v2/merchant/virtual/accounts \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "merchantId": 100001,
    "fiat": "MXN",
    "paymentId": 105,
    "alias": "CUST0001"
  }'
```

```json Response theme={null}
{ "code": 200, "msg": "SUCCESS", "data": { "fiat": "MXN", "status": 1 } }
```

渠道开设账户期间 `status` 为 `1`（待处理），激活后为 `2`，失败则为 `3`。ARS（`63`）账户会立即返回 `2`。在别名处于待处理状态时再次发送相同别名会返回 `-5085`；激活后再次发送则返回 `-5086`。

**2. 获取该别名的银行信息**

使用 `depositAlias` 轮询 [`GET /v2/merchant/virtual/addfunds`](https://docs.velafi.com/cn/api-reference/merchant/get-multiple-virtual-account)，直到记录的 `status` 为 `2`，然后读取其 `fieldList`。键名取决于渠道，详见[各支付方式的 `fieldList` 键](https://docs.velafi.com/cn/api-reference/merchant/get-pending-fund-account#fieldlist-keys-by-payment-method)。

```bash cURL theme={null}
curl -G https://api.velafi.com/v2/merchant/virtual/addfunds \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  --data-urlencode "merchantId=100001" \
  --data-urlencode "fiat=MXN" \
  --data-urlencode "paymentId=105" \
  --data-urlencode "depositAlias=CUST0001"
```

将这些信息与付款人关联保存。`fieldList` 中的二维码图片链接在响应后一小时过期，因此再次展示时请重新获取。如需为商户主账户注资，请改为调用 [`GET /v2/merchant/addfunds`](https://docs.velafi.com/cn/api-reference/merchant/get-pending-fund-account)。

**3. 告知付款人如何操作**

向付款人展示其别名对应的信息。付款人的操作取决于支付通道：

| 支付通道 | 付款人的操作 |
| - | - |
| MXN，SPEI（Finco Pay `105`、Tesored `72`） | 向 CLABE（`Cuenta CLABE` 或 `clabeNumber`）发起 SPEI 转账。 |
| ARS，CBU/CVU（Momentum `63`） | 向 `CVU Number`（如有，也可使用其 `Alias`）发起银行转账。 |
| COP，自动 ACH（`68`） | 打开 `paymentLink` 并付款。 |
| COP，Bre-B（`69`） | 向 `brebKey` 发起 Bre-B 转账。 |
| BRL，Pix（Genial `90`） | 向 Pix 密钥（`Chave Pix - Random Pix`）付款，或使用复制粘贴码或二维码付款。 |
| BRL，Pix - Woovi（Avenia `92`） | 扫描静态 Pix 二维码（`qrCodeLink`、`qrCode`）付款，或在提供 `pixKey` 时向其付款。 |

**4. 处理充值 Webhook**

充值入账后，VelaFi 会创建一条类型为 `DEPOSIT`、状态为 `2` 的资金记录，并发送 `FUNDING_WEBHOOK`。请验证 `signature` 请求头、保存该事件，并返回 HTTP `200` 和 `{"callbackStatus":"SUCCESS"}`。在您的账本中为 `depositAlias` 所标识的付款人入账。参见[需要处理的 Webhook](#webhooks-to-handle)。

**5. 检查余额**

通过 [`GET /v2/merchant/accounts`](https://docs.velafi.com/cn/api-reference/merchant/get-a-list-of-merchant-accounts) 读取商户余额：即该币种和渠道对应记录的 `balance`。这是可用于出金、划转和入金订单的金额。

```bash cURL theme={null}
curl -G https://api.velafi.com/v2/merchant/accounts \
  -H "X-BH-TOKEN: YOUR_TOKEN" \
  --data-urlencode "merchantId=100001" \
  --data-urlencode "fiat=MXN"
```

## 需要处理的 Webhook

订阅 `FUNDING_WEBHOOK`。一个 Webhook 会接收您账户下所有商户的事件。充值事件示例如下（所有值均为字符串）：

```json FUNDING_WEBHOOK (DEPOSIT) theme={null}
{
  "webhookId": "ebab8a9663704e7cbbebe672c7c67912",
  "eventType": "FUNDING_WEBHOOK",
  "txId": "1123123123",
  "merchantId": "100001",
  "fiat": "MXN",
  "totalAmount": "1000",
  "amount": "1000",
  "fee": "0",
  "paymentId": "105",
  "type": "DEPOSIT",
  "status": "2",
  "depositAlias": "CUST0001",
  "payerName": "Example Payer",
  "payerAccount": "000000000000000002",
  "bankWebhookInfo": "{...}",
  "completedTime": "1737452344000",
  "createTime": "1737452292000",
  "updateTime": "1737452344000",
  "timestamp": "1737452344512"
}
```

| 字段 | 用途 |
| - | - |
| `txId` | 标识资金记录。与 `eventType` 和 `status` 一起作为您的幂等键。 |
| `type` | 路由事件。充值为 `DEPOSIT`。同一 Webhook 还会推送 `WITHDRAW` 和 `BUY_CRYPTO`。商户之间的划转不会推送。 |
| `status` | `2` 已完成，`3` 已取消，`4` 已退款。待处理的记录不会推送。 |
| `depositAlias` | 将充值归属到付款人的虚拟账户。 |
| `amount`、`fee`、`totalAmount` | 记录净额和手续费。 |
| `payerName`、`payerAccount`、`taxId`、`cardNo` | 记录汇款人信息。仅在支付通道提供时才会发送，因此请将其视为可选字段。 |
| `bankWebhookInfo` | 以 JSON 字符串形式提供的服务商特定信息，例如 SPEI 的 `tracking_id` 或 ARS 的 `idCoelsa`。参见[银行 Webhook 信息详情](https://docs.velafi.com/cn/api-reference/webhooks/funding-records-message-push.md#bank-webhook-info-details)。 |

完整字段列表见[资金记录事件](https://docs.velafi.com/cn/api-reference/webhooks/funding-records-message-push.md)。

> [!WARNING]
>
> 只有当您的端点返回 `2xx` 状态码**并且**返回 JSON 响应体 `{"callbackStatus":"SUCCESS"}` 时，推送才算成功。请尽快响应：VelaFi 最多等待 60 秒，超时即视为推送失败。纯文本 `SUCCESS`、`{"received":true}`、空响应体或您自己的错误 JSON 均视为失败。连续三次推送失败后，该事件将不再发送，且 Open API 没有重新推送的端点。请先确认接收，再异步处理。参见[推送与重试](https://docs.velafi.com/cn/api-reference/webhooks/webhook-setup.md#delivery-and-retries)。

## 处理失败

* **重复或乱序的事件。** 同一事件可能到达不止一次，而在推送前状态已发生变化的事件会被丢弃。请基于 `eventType` + `txId` + `status` 实现幂等处理，并在需要最新状态时通过[获取资金记录](https://docs.velafi.com/cn/api-reference/merchant/retrieve-funding-records.md)读取该记录。
* **错过的 Webhook。** 如果您的端点宕机或响应不正确，事件不会重发。请定期运行下文的对账流程，确保不遗漏任何充值。
* **没有 `depositAlias` 的充值。** 付款到商户主账户信息的充值，或不回传别名的支付通道，都没有可匹配的虚拟账户。请利用付款人字段和 `bankWebhookInfo` 将其转入人工审核。
* **虚拟账户创建失败。** `status` `3` 表示渠道拒绝了该账户。`-5079` 表示该账户未针对该币种和渠道开通，`-5071` 表示商户在该渠道上的币种账户未激活。重试前请检查商户账户。
* **COP 别名被拒绝。** 对于 `68` 和 `69`，别名必须为 6 到 21 位大写字母或数字。

## 对账

资金记录是余额入账情况的唯一可信来源：

* 使用 [`GET /v2/merchant/funding/records`](https://docs.velafi.com/cn/api-reference/merchant/retrieve-funding-records)，传入 `type=DEPOSIT`、一个 `fiat` 以及 `startTime`/`endTime` 时间窗口（该窗口按完成时间计算）。将每条状态为 `2` 的记录与您保存的 Webhook 进行比对，并处理遗漏的记录。对于充值，`webhookInfo` 包含与 `bankWebhookInfo` 相同的服务商信息，其中包括 `depositAlias`。
* 使用 [`GET /v2/merchant/fiat/flows`](https://docs.velafi.com/cn/api-reference/merchant/get-a-list-merchant-fiat-flow) 获取逐笔余额历史：每一行包含变动额（`changed`）、变动后余额（`total`）以及相关的 `txId`。用它来证明[获取商户账户列表](https://docs.velafi.com/cn/api-reference/merchant/get-a-list-of-merchant-accounts.md)中的余额等于您所有变动之和。

资金记录默认每页返回 100 条（通过 `pageSize` 最多 20,000 条），法币流水每页最多 1,000 条。使用 `currentPage` 翻页。

## 在沙盒环境中测试

使用 `https://api-test.velafi.com` 和沙盒环境凭证。您可以在沙盒环境中创建和查询虚拟账户，并使用[法币充值模拟器](https://docs.velafi.com/cn/docs/sandbox.md#sandbox-testing-tools)（`POST /v2/platform/test/deposit`）入账测试充值。传入 `depositAlias` 可将充值发送到某个虚拟账户。

* **Webhook 不会在沙盒环境中触发。** 请自行向处理程序发送示例负载进行测试，并通过[获取资金记录](https://docs.velafi.com/cn/api-reference/merchant/retrieve-funding-records.md)检查每笔模拟充值的结果。
* 模拟器只能生成成功的充值，无法生成失败或被退回的充值。

## 上线检查清单

* [ ] `FUNDING_WEBHOOK` 端点会验证签名，并快速返回 HTTP `200` 和 `{"callbackStatus":"SUCCESS"}`，远在 60 秒超时之内。
* [ ] 处理程序基于 `eventType` + `txId` + `status` 实现幂等，并忽略已处理过的事件。
* [ ] 每个付款人都有自己的虚拟账户，且别名对应您系统中的唯一一位客户。
* [ ] 您的账本维护每个付款人的余额；您不期望 VelaFi 为每个虚拟账户单独维护余额。
* [ ] 没有 `depositAlias` 的充值会进入审核队列。
* [ ] 有定时任务将资金记录（`type=DEPOSIT`）与保存的 Webhook 进行比对，并处理缺失的部分。
* [ ] 二维码和付款链接在展示前会重新获取。

另请参阅通用的[上线检查清单](https://docs.velafi.com/cn/docs/use-cases/go-live-checklist.md)。


## Related topics

- [从余额支付本地货币](https://docs.velafi.com/cn/docs/use-cases/payouts-from-balance.md)
- [核心使用场景](https://docs.velafi.com/cn/docs/use-cases/overview.md)
- [将本地货币兑换为稳定币](https://docs.velafi.com/cn/docs/use-cases/convert-to-stablecoins.md)
- [将您的客户注册为商户](https://docs.velafi.com/cn/docs/use-cases/onboard-your-customers.md)
- [Agent Skills](https://docs.velafi.com/cn/docs/developer-tools/agent-skills.md)


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