跳到主要内容

Webhook URL

概述

该功能把已支付收款单的数据送达商户的服务器,让商户的店铺能自动处理付款,并向买家交付商品或服务。

Webhook URL 按项目单独设置,指向商户店铺内的付款处理脚本。地址必须使用 HTTPS 和域名:不接受 IP 地址,且每次投递都会校验证书。

每当收款单状态变为已支付 (Paid),服务就向该地址发送如下格式的 POST 请求:

{
"wallet":{
"id":"47aa71e2-07a0-482e-9172-7114d7376ba0",
"name":"usdt-tron",
"blockchain":"tron",
"cryptocurrency":"usdt",
"address":"TKbstUwMzLrfTAGL4erYb7gc7ghmHQ9zG7"
},
"project":{
"id":"9deea1e2-0c08-41a3-bdc2-a34eada3892d",
"name":"My project",
"commissionPayer":"seller",
"commissionRate":1
},
"invoice":{
"id":"a4c9e2ee-9a03-43e5-a1a1-00caf679d16a",
"uid":"AFhygKX21ecd",
"createDatetime":"2024-02-26 13:29:24",
"timeToPayDatetime":"2024-02-27 01:29:24",
"commissionFiatUSD":0.05,
"amountFiatUSD":5.02,
"amountFiat":5,
"calcAmountFiat":5.02,
"currencyFiat":"USD",
"description":null,
"serviceData":null,
"status":"paid"
},
"payment":{
"id":"f986ad8d-2298-473d-982a-efbc817b975d",
"amount":5.02,
"hash":"74763b65e43bcc9492a6ce9a7f26fbfdbd7635aecd3454420b5e9534cba50ee6",
"transactionDatetime":"2024-02-26 13:32:57"
}
}

每次转为已支付都会发送通知——无论是服务自动找到付款,还是商户手动把付款关联到收款单。

请求参数

参数说明
wallet.id钱包 ID,UUID 格式
wallet.name钱包名称
wallet.blockchain加密钱包所在的区块链
wallet.cryptocurrency钱包的加密货币
wallet.address加密钱包地址
project.id项目 ID,UUID 格式
project.name项目名称
project.commissionPayer服务费由谁承担
project.commissionRate费率,单位为 %
invoice.id收款单 ID,UUID 格式
invoice.uid收款单 ID(面向买家)
invoice.createDatetime收款单创建日期和时间 (UTC)
invoice.timeToPayDatetime收款单对买家有效的截止日期和时间 (UTC)。付款检索在此时刻之后再持续 1 小时——照顾慢速网络。因此已显示为过期的收款单也可能收到通知
invoice.commissionFiatUSD服务费金额,按 invoice.amountFiatUSD 金额计算
invoice.amountFiatUSD以 USD 计的金额。创建收款单时按当时汇率由 invoice.amountFiat 换算。付款时被实际收到的金额覆盖,按付款时刻的汇率折算成 USD。invoice.commissionFiatUSD 中的服务费也随之重算
invoice.amountFiat收款单的法币原始金额,不会改变
invoice.calcAmountFiat按付款时刻的加密货币汇率折算成 invoice.currencyFiat 币种的金额。它可能与 invoice.amountFiat 不同:买家未必在创建后立即支付。这段时间里,加密货币对 invoice.currencyFiat 的汇率可能向任一方向变动
invoice.currencyFiat法币币种
invoice.description创建收款单时填写的描述
invoice.serviceData创建收款单时填写的服务数据
invoice.status收款单状态
payment.id付款 ID,UUID 格式
payment.amount以加密货币计的付款金额
payment.hash链上交易哈希
payment.transactionDatetime链上交易的日期和时间 (UTC)

通知签名

每个请求都用 Webhook 密钥签名。签名放在 X-TimestampX-Signature 请求头中,用来确认通知来自服务本身,而不是得知处理程序地址的外人。

处理订单之前先验证签名。签名机制和现成示例见 Webhook 签名验证

处理建议

不要因为支付期限已过就拒绝通知。“收款单已过期,所以付款无效”这样的检查看似合理,却会砍掉一部分真实付款:慢速网络上交易可能在期限之后才确认,商户也可以手动把付款关联到已过期的收款单。通知本身即是付款的确认。

用原始字段 invoice.amountFiat 核对金额。它是收款单开出时的金额,不会改变。amountFiatUSD 字段反映实际收到的金额,可能与开出的不同——既因为汇率波动,也因为手动关联付款。

把金额当作数字解析。末尾的零会被去掉:金额 10.00 送达时是 10,展示格式在自己一侧处理。低于 0.0001 的金额以科学计数法送达,例如 1.0e-6——标准 JSON 解析会得到正确的数字,只有手动按字符串解析才会出错。

以幂等方式处理通知。同一通知可能再次送达——例如脚本成功处理了付款却返回了非 2xx 状态码。发货之前,检查该 invoice.id 是否已经处理过。

输出时转义值invoice.descriptioninvoice.serviceData 字段按商户提交时的原样返回。要在 HTML 中渲染它们,请在自己一侧转义。

投递计划

Webhook URL 上的服务器必须返回 2xx HTTP 状态码。其他状态码、超时或连接中断都视为投递失败。

不跟随重定向:返回 301 或 302 是投递失败,而不是跳到新地址。请设置处理程序的最终地址。

建立连接限时 5 秒,整个请求限时 10 秒。处理程序超出这个时间,投递计为失败。

投递失败后,服务按以下计划重试:

  • 上次投递失败后 5 分钟
  • 15 分钟后
  • 30 分钟后
  • 1 小时后
  • 3 小时后
  • 6 小时后
  • 12 小时后
  • 24 小时后

此后停止投递尝试。

停用 Webhook URL

有时店铺的 Webhook 脚本正确处理了付款,却返回非 2xx 状态码。这会让服务器按上述计划频繁重试,给双方的服务器都带来额外负载。

为防止这种情况,服务设有在项目中停用 Webhook URL 的机制。要避免触发它,请按以下步骤操作:

  1. 修改 Webhook 处理程序代码,让它在成功处理付款时返回 2xx 状态码,通常是 200。用任意模拟工具测试,例如 Postman。
  2. 联系技术支持修正设置。
  3. 在项目设置中重新启用 Webhook URL 并保存项目。