Payin 收款对接指南
本文档面向商户开发者,说明如何创建 Payin 收款订单、引导用户付款、处理订单 Webhook,并通过查询接口确认最终结果。
Payin 主流程分为三步:
- 创建收款订单:商户调用
POST /payment/acquiring/orders创建订单。 - 用户完成付款:商户将用户引导到
checkout_url,用户选择币种和网络并付款。 - 确认结果:商户通过
acquiring.order.updatedWebhook 接收订单状态变化,也可以调用查询接口做补偿确认和对账。
一页摘要
最小 API 集合:
POST /payment/acquiring/ordersGET /payment/acquiring/orders/{order_id}
补充 API:
GET /payment/acquiring/orders/{order_id}/payments:查询该订单下的支付记录POST /payment/acquiring/orders/{order_id}/close:提前关闭未完成订单
最小 Webhook:
acquiring.order.updated:订单状态变化
如果商户需要接收 Webhook,创建订单时应传入有效的 notify_webhook_id。该 webhook 必须处于启用状态,并订阅 acquiring.order.updated、acquiring.payment.updated 或 acquiring.*。
接入前准备
正式创建收款订单前,先确认这些信息:
| 项目 | 为什么需要 |
|---|---|
| API Key 权限 | 创建订单需要 acquiring 创建权限,查询订单需要 acquiring 读取权限,关闭订单需要 acquiring 关闭权限。 |
| 收款方式 | 确认当前账号可用的支付 token,例如 TRON_USDT、BSC_USDT。 |
| 商户订单号 | 每笔都必须传 out_trade_no,并在商户系统内保持唯一。 |
| Webhook 配置 | 需要先在商户后台创建并启用 webhook,然后每次创建订单都传 notify_webhook_id。 |
| 商户侧存储 | 至少保存 out_trade_no、order_id、status、checkout_url、expire_time。 |
确认可用支付方式
首次接入或新增收款路线时,商户需要先知道用户可以用哪些币种和网络付款。
支付 token ID 表示“网络 + 币种”的组合,格式通常是:
<NETWORK>_<CURRENCY>
例如:
| 支付 token ID | 含义 | 用户实际支付 |
|---|---|---|
TRON_USDT | TRON 网络上的 USDT | 用户通过 TRON 转 USDT |
ETH_USDT | Ethereum 网络上的 USDT | 用户通过 Ethereum 转 USDT |
BSC_USDT | BNB Smart Chain 网络上的 USDT | 用户通过 BSC 转 USDT |
ETH_USDC | Ethereum 网络上的 USDC | 用户通过 Ethereum 转 USDC |
BASE_USDC | Base 网络上的 USDC | 用户通过 Base 转 USDC |
需要确认:
| 你需要的值 | 示例 | 用在请求哪里 |
|---|---|---|
| 订单计价币种 | USD | order_currency |
| 支付 token ID | TRON_USDT、BSC_USDT | allowed_pay_currencies,不传则使用系统默认可用 token |
| Webhook ID | webhook_xxx | notify_webhook_id |
这些值通常由 Beyounger 或商户后台配置确认。商户创建订单时可以把允许用户支付的 token ID 放入 allowed_pay_currencies;如果不传,则使用系统为该账号配置的默认可用 token。
当前常见 token ID:
| 币种 | 可用 token ID |
|---|---|
| USDT | TRON_USDT、ETH_USDT、BSC_USDT、MATIC_USDT、ARBITRUM_USDT、SOL_USDT |
| USDC | ETH_USDC、BASE_USDC、BSC_USDC、MATIC_USDC、ARBITRUM_USDC、SOL_USDC |
建议:
- 只把商户希望开放给用户的 token ID 放进
allowed_pay_currencies。 - 如果只想让用户用 TRON USDT 支付,就传
["TRON_USDT"]。 - 如果允许用户在多个网络支付 USDT,可以传
["TRON_USDT", "ETH_USDT", "BSC_USDT"]。 - 不要只传
USDT或USDC,必须传完整 token ID。 - 不要把未开通或不准备支持的 token ID 放进订单。
核心流程图
第一步:创建收款订单
接口
POST /payment/acquiring/orders
商户通过该接口创建一笔收款订单。创建成功后,Beyounger 返回 checkout_url,商户前端应将用户跳转到该地址完成支付。
请求头
Authorization: Bearer <api_key_jwt>
Content-Type: application/json
Accept: application/json
核心请求参数
| 字段 | 是否必填 | 说明 |
|---|---|---|
out_trade_no | 必填 | 商户订单号,必须每笔唯一 |
order_currency | 必填 | 订单计价币种,当前支持 USD |
order_amount | 必填 | 订单金额,必须大于 0 |
allowed_pay_currencies | 可选 | 限制用户可支付的 token 列表,例如 ["TRON_USDT", "BSC_USDT"];不传则使用系统默认可用 token |
expire_seconds | 必填 | 订单有效期,范围 60 到 10800 秒 |
underpay_tolerance | 必填 | 少付容差,必须大于等于 0 |
notify_webhook_id | 必填 | 接收订单状态通知的 webhook ID |
redirect_url | 可选 | 用户完成支付后跳转地址,支持 HTTPS 绝对地址或同源相对路径 |
logo_url | 可选 | 收银台展示的商户 Logo,必须是 HTTPS 地址 |
remark | 可选 | 商户备注 |
创建订单示例
{
"out_trade_no": "payin_202606190001",
"order_currency": "USD",
"order_amount": "20.00",
"allowed_pay_currencies": ["TRON_USDT", "BSC_USDT"],
"expire_seconds": 1800,
"underpay_tolerance": "0",
"notify_webhook_id": "webhook_xxx",
"redirect_url": "https://merchant.example.com/payment/result",
"remark": "Order payin_202606190001"
}
成功响应
{
"code": 0,
"message": "OK",
"data": {
"order": {
"order_id": "acq_order_xxx",
"platform_order_no": "P202606190001",
"out_trade_no": "payin_202606190001",
"status": "pending",
"checkout_type": "default",
"order_currency": "USD",
"order_amount": "20.00",
"allowed_pay_currencies": ["TRON_USDT", "BSC_USDT"],
"pay_amount": "20.00",
"paid_amount_total": "0",
"remaining_amount": "20.00",
"underpay_tolerance": "0",
"checkout_url": "https://api.example.com/payment/checkout/acq_order_xxx",
"notify_webhook_id": "webhook_xxx",
"expire_time": 1781789497,
"created_at": 1781787697,
"updated_at": 1781787697
}
}
}
必须保存:
out_trade_noorder_idstatuscheckout_urlallowed_pay_currencies,如果请求中有传pay_amountexpire_time
创建成功不代表用户已经付款,只代表收款订单已经创建。
第二步:用户付款和 Webhook 通知
商户前端应跳转到 checkout_url,或在自己的页面展示该地址。用户完成付款后,Beyounger 会根据链上或服务商结果更新订单状态。
如果创建订单时传了有效的 notify_webhook_id,订单达到需要通知的状态时,Beyounger 会发送:
acquiring.order.updated
商户收到后应:
- 校验 Webhook 签名
- 按
event_id或business_id做幂等 - 读取
data.order_id、data.out_trade_no、data.status - 必要时调用
GET /payment/acquiring/orders/{order_id}确认最新状态 - 更新商户订单状态
Webhook Payload 示例
{
"event_id": "acqevt_acq_order_xxx",
"event_type": "acquiring.order.updated",
"business_type": "acquiring",
"business_id": "acq_order_xxx",
"occurred_at": 1781789497,
"version": "v1",
"data": {
"provider_event": "transaction_confirmed",
"anomaly_tag": "",
"order_id": "acq_order_xxx",
"platform_order_no": "P202606190001",
"out_trade_no": "payin_202606190001",
"previous_status": "pending",
"status": "completed",
"status_changed": true,
"amount_changed": true,
"order_currency": "USD",
"pay_amount": "20.00",
"paid_amount_total": "20.00",
"remaining_amount": "0",
"overpaid_amount": "0",
"underpay_tolerance": "0",
"expire_time": 1781789497,
"updated_at": 1781789497
}
}
核心字段:
| 字段 | 说明 |
|---|---|
event_id | Webhook 事件 ID |
event_type | 固定为 acquiring.order.updated |
business_type | 固定为 acquiring |
business_id | 等于 order_id |
data.out_trade_no | 商户订单号 |
data.status | 最新订单状态 |
data.paid_amount_total | 已支付总金额 |
data.remaining_amount | 剩余应付金额 |
data.anomaly_tag | 异常标记,例如过期后到账 |
数币收单状态说明
数币收单不是简单的“成功/失败”模型。订单状态由该订单下的支付记录聚合而来,核心判断依据是已确认到账金额、订单应付金额、少付容差和订单是否过期。
商户处理 Webhook 时建议按下面规则理解:
Webhook 中的 data.status | 是否最终状态 | 说明 | 商户建议 |
|---|---|---|---|
partial_paid | 否 | 已有部分金额完成确认,但确认金额还没有达到 pay_amount - underpay_tolerance | 订单不要标记成功,继续等待后续到账或按商户规则提示用户补款 |
completed | 是 | 已确认金额加上少付容差后满足订单应付金额 | 标记商户订单支付成功,开始发货、入账或开通服务 |
underpaid | 是 | 订单过期时已有确认金额,但金额不足且超过少付容差 | 标记异常订单,进入人工处理、补款或退款流程 |
expired | 是 | 订单过期且没有确认到账金额 | 标记订单过期,不再让用户继续使用该订单付款 |
同时注意:
pending、confirming、processing更常见于查询接口或支付记录中,通常表示还在等待用户付款、链上广播或确认数。paid_amount_total是已确认到账金额,不是用户可能已经广播但尚未确认的金额。remaining_amount是基于已确认到账金额计算的剩余金额。overpaid_amount大于 0 表示用户多付,商户需要按业务规则处理多付金额。anomaly_tag=expired_paid表示订单过期后又检测到到账,商户不要自动按正常成功处理,应进入异常流程。- 同一个订单可能有多笔支付记录,订单状态以聚合后的
data.status为准。
第三步:查询订单状态
接口
GET /payment/acquiring/orders/{order_id}
调用场景:
- 创建后查看初始状态
- 收到 Webhook 后确认最新状态
- Webhook 超时或丢失时补偿查询
- 财务或运营对账
状态判断
status | 含义 | 商户处理 |
|---|---|---|
pending | 等待用户付款 | 保持订单待支付 |
processing | 已检测到支付,处理中 | 等待后续状态 |
confirming | 等待链上确认 | 等待确认完成 |
partial_paid | 已部分支付 | 继续等待或按商户规则处理 |
completed | 支付完成 | 标记商户订单支付成功 |
underpaid | 少付且超过容差 | 标记异常,进入人工或退款流程 |
expired | 订单已过期 | 标记订单过期;如果后续到账,关注 anomaly_tag |
最终成功以 status=completed 为准。不要只根据前端跳转结果或创建订单响应判断支付成功。
查询支付记录
接口
GET /payment/acquiring/orders/{order_id}/payments
这个接口用于排查和对账,不是最小接入必须接口。常见用途:
- 查看用户选择的支付币种和网络
- 查看收款地址
- 查看
tx_hash - 排查少付、多付、币种或网络不匹配
支付记录常见状态:
payment.status | 含义 |
|---|---|
pending | 等待支付 |
processing | 已收到支付,处理中 |
confirming | 等待确认 |
completed | 该笔支付完成 |
failed | 支付失败 |
late | 过期后到账 |
expired | 支付记录过期 |
关闭订单
接口
POST /payment/acquiring/orders/{order_id}/close
如果商户订单已取消、已换单,或不希望用户继续付款,可以关闭收款订单。
{
"reason": "merchant_order_cancelled"
}
关闭订单只适用于未完成订单。订单已经支付成功后,不应通过关闭接口处理。
常见问题
创建订单成功是否代表支付成功?
不是。创建成功只代表收款订单已创建。最终支付结果看 acquiring.order.updated Webhook 或查询接口。
Payin 是否支持单笔 notify_url?
当前创建订单接口使用 notify_webhook_id 指定回调配置,不使用单笔 notify_url。商户需要先创建 webhook,再在订单中传 notify_webhook_id。
allowed_pay_currencies 怎么传?
如果商户想限制用户只能使用指定币种或网络支付, 就传 allowed_pay_currencies。如果不传,系统会使用该账号默认可用的支付 token。
传入时使用 Beyounger 或商户后台确认过的支付 token ID。token ID 是“网络 + 币种”,例如 TRON_USDT 表示 TRON 网络上的 USDT。
示例:
{
"allowed_pay_currencies": ["TRON_USDT", "BSC_USDT"]
}
Webhook 和查询接口哪个为准?
Webhook 用于实时通知,查询接口用于确认和补偿。建议两者都接入。