跳转到主要内容
使用此流程从商户的法币余额(也称为待处理资金 / Pending Fund 余额)向您已保存为收款人的银行账户或 Pix 密钥支付本地货币(MXN、ARS、COP、BRL、PEN)。您调用 POST /v2/merchant/claimfunds,VelaFi 从余额中扣款并通过本地支付通道发出付款,随后通过 FUNDING_WEBHOOK 告知您付款是否完成。同一余额也可以通过 POST /v2/merchant/transfer 划转给您的另一个商户。 余额通常来自充值。参见使用虚拟账户收取本地付款。

工作原理

开始之前

  • API 访问权限。 一个 API 密钥、已加入白名单的服务器 IP,以及放在 X-BH-TOKEN 请求头中的业务令牌。参见认证。
  • 一个已验证的商户,且在支持出金的渠道上拥有已激活的币种账户(见下文)。参见激活商户账户。
  • 该币种账户上有余额,来自同一渠道的充值。参见使用虚拟账户收取本地付款。
  • 一个 FUNDING_WEBHOOK 端点,已注册并能返回所要求的确认响应。参见 Webhook 设置。

支持从余额出金的渠道

每笔出金都适用以下三条规则:
  1. 同一渠道。 出金通过持有该余额的币种账户所在渠道发出。只有通过该渠道(或通过 VelaFi Pending Fund)入账的余额才能在该渠道出金。
  2. 同一商户币种账户。 收款人必须保存在同一商户下,且币种和渠道与该账户相同。保存在其他商户下、或属于其他渠道的收款人(例如使用 Tesored 收款人对应 Finco Pay 余额)会被拒绝。
  3. 金额加手续费。 余额必须足以覆盖 amount 加出金手续费。

分步操作

1

保存收款人

通过 GET /v2/payments/templates 获取该渠道的字段模板,然后通过 POST /v2/payments 在持有余额的商户下保存目标账户。各渠道的模板参见管理收款人。
cURL
保存返回的 id:它就是出金所用的 userPaymentId。只向 status 为 1(有效)的收款人出金。如果该账号已被保存,响应中的 status 为 3 并带有 sameAccountNumberId;请使用该 ID,而不要新建记录。
2

检查余额

通过 GET /v2/merchant/accounts 读取该商户、币种和渠道对应的 balance。请为手续费预留空间。
3

创建出金

调用 POST /v2/merchant/claimfunds。务必传入您自己的唯一 clientId。
cURL
Response
amount 是收款人收到的金额。fee 是为该渠道和您的账户设定的出金手续费,调用成功时会从余额中扣除 totalAmount(amount + fee)。金额会按该币种的精度向下取整。200 响应表示出金已被受理,而不表示资金已到账:在 Webhook 或资金记录显示其他状态之前,出金都处于待处理状态。
4

等待结果

处理该 txId 对应的 type 为 WITHDRAW 的 FUNDING_WEBHOOK(参见需要处理的 Webhook)。如果没有收到,请使用 txId 或 clientId 通过 GET /v2/merchant/funding/records 读取该记录。

出金状态

FUNDING_WEBHOOK 会针对 2、3 和 4 发送,待处理状态不会发送。

需要处理的 Webhook

出金事件是 type 为 WITHDRAW 的 FUNDING_WEBHOOK。提现的 totalAmount 为负数。
FUNDING_WEBHOOK (WITHDRAW, canceled)
  • 通过 clientId 或 txId 将事件与您的出金匹配。
  • 基于 eventType + txId + status 实现幂等处理。同一事件可能到达不止一次,并且出金之后可能从 2 变为 4,因此请处理完成后又发生退款的情况。
  • failCode 和 failReason 仅在已取消且有记录原因的出金中发送。很多失败并不附带原因;请勿依赖它们来决定后续操作。
  • bankOrderId 是该转账在支付服务商处的参考号(如有)。请保存以备支持请求使用。
  • 快速返回 HTTP 200 和 {"callbackStatus":"SUCCESS"}。VelaFi 最多等待 60 秒;超时或任何其他响应都视为推送失败。参见推送与重试。
完整字段列表见资金记录事件。

处理失败

创建出金时的错误

如果 claimfunds 返回错误,则不会创建资金记录,也不会扣款。常见错误码(参见错误码):

超时与重试

只要您复用相同的 clientId,clientId 校验就能确保重试是安全的:
  1. 如果调用超时或返回网络错误,不要生成新的 clientId。通过 GET /v2/merchant/funding/records?clientId=... 查询该出金。
  2. 如果存在记录,说明出金已创建:跟踪其状态。
  3. 如果不存在,使用相同的 clientId 再次发送相同请求。如果第一次请求实际上已成功,您会收到 -1174,而不会产生第二笔出金。
重复的 clientId 会返回 -1174 错误,而不是原出金。请从资金记录中读取原出金。

失败的出金

当出金最终状态为 3 时,完整的 totalAmount 会退回余额。clientId 不能复用,即使对应的出金失败也不行,因此如需重试:
  1. 检查收款人信息(账号、密钥类型、户名),必要时更正或重新保存收款人。
  2. 使用新的 clientId(例如 payout-0001-r1)创建新的出金,并在您的系统中将其与原出金关联。
不要在循环中自动重试。如果同一收款人在没有 failReason 的情况下反复失败,请携带 txId 和 bankOrderId 联系 VelaFi 支持团队。

在商户之间划转余额

如需在不经银行转账的情况下将余额从您的一个商户划转到另一个商户,请使用 POST /v2/merchant/transfer。两个商户都必须属于您的账户,并且在支持出金的渠道上拥有相同 fiat 和 paymentId 的已激活币种账户。
1

查询手续费

使用 fiat 调用 GET /v2/merchant/transfer_fee。feeType 0 表示固定金额,1 表示按金额比例收取(0.01 = 1%)。划转本身返回的 fee 才是实际收取的金额。
2

创建划转

cURL
转出方在该渠道上必须有 fiatAmount + 手续费的可用余额。划转在同一次调用中完成:响应返回 fromId(转出方的 TRANSFER_OUT 记录)和 toId(接收方的 TRANSFER_IN 记录),状态均为 2。接收方收到 fiatAmount,转出方被扣除 totalFiatAmount。
划转与出金遵循相同的 clientId 规则:已被您账户下任何资金记录使用的 clientId 会返回 -1174。请始终传入该值,以便在超时后查询划转。在资金记录中,TRANSFER_OUT 记录带有您的 clientId;TRANSFER_IN 记录带有 TRANSFER_IN_ 加上您的 clientId。请通过 txId(fromId、toId)查询这两条记录。

对账

  • GET /v2/merchant/funding/records 是每笔出金和划转的唯一可信来源。按 type=WITHDRAW(或 TRANSFER_OUT、TRANSFER_IN)、fiat 和时间窗口筛选,检查您创建的每笔出金都已有最终状态(2、3 或 4)。对一直处于待处理状态的出金进行排查。
  • GET /v2/merchant/fiat/flows 显示每一笔余额变动:创建出金时为 WITHDRAW,已取消或已退款的出金退回余额时为 WITHDRAW_ROLLBACK,划转则为 TRANSFER_OUT / TRANSFER_IN。每一行的 total 是该笔变动后的余额。

在沙盒环境中测试

使用 https://api-test.velafi.com 和沙盒环境凭证。使用法币充值模拟器为测试商户注资,保存一个收款人,然后基于该余额调用 claimfunds 和 transfer。可借此测试您的请求校验、上述错误码以及基于 clientId 的重试逻辑。
  • Webhook 不会在沙盒环境中触发。 请通过获取资金记录跟踪每笔出金,并使用示例负载测试您的 Webhook 处理程序,包括已取消(3)和已退款(4)的提现。
  • 模拟器无法生成失败或被退回的充值。

上线检查清单

  • 每笔出金和划转都传入唯一的 clientId,且您在调用前已保存该值。
  • 超时时,您会在重试前先查询该 clientId,并使用相同的 clientId 重新发送。
  • 失败的出金只会在检查收款人信息后,使用新的 clientId 重试。
  • 收款人保存在与余额相同的商户和渠道下,且只使用 status 为 1 的收款人。
  • 余额检查包含手续费。
  • FUNDING_WEBHOOK 处理程序能处理状态为 2、3 和 4 的 WITHDRAW,并能在缺少 failReason 时正常工作。
  • 有定时任务标记超过预期结算时间仍处于待处理状态的出金。
另请参阅通用的上线检查清单。