充值回调
验证通知来源,可靠地把充值结果记入业务账本。
接收通知
在开发者设置配置回调地址,并保存独立回调密钥。仅支持公网 HTTPS 443 端口,不跟随重定向。达到确认要求后,平台发送 JSON 格式的 POST 请求,请在服务端接收。
| 事件 | 场景 |
|---|---|
deposit.confirmed | 用户地址收到充值,未匹配到业务订单 |
payment.paid | 订单支付完成,或测试收款确认完成 |
webhook.test | 控制台手动发出的连通性测试,无资金变动 |
无订单充值通知结构示意:
{
"event": "deposit.confirmed",
"chain": "bsc",
"asset": "BEP20-USDT",
"customer_id": "<平台用户UUID>",
"customer_ref": "customer_1001",
"deposit_address": "<用户充值地址>",
"amount": "12.50",
"tx_hash": "<链上交易哈希>",
"confirmations": 15
}这里的确认数仅用于示意,实际要求以平台链配置为准。订单支付通知包含 order_id、customer_id、asset、amount、tx_hash 和 confirmations;不要假定所有事件都包含 customer_ref 或 order_no。
验证回调签名
请求头 X-Webhook-Signature 是实际请求正文原始字节的 HMAC-SHA256 十六进制签名,密钥为独立回调密钥。X-Webhook-ID 标识本条通知,重试时保持不变。
先读取原始正文验签,再解析 JSON。不要排序、格式化或重新序列化正文。回调密钥轮换后,后续投递(包括历史通知重试)使用当前密钥,请同步更新接收端配置。
import hashlib
import hmac
import json
def verify_webhook(raw_body: bytes, signature: str, secret: str) -> bool:
if len(signature) != 64:
return False
try:
expected = hmac.new(secret.encode(), raw_body,
hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, signature.lower()):
return False
return isinstance(json.loads(raw_body), dict)
except (ValueError, TypeError, UnicodeError):
return False幂等入账
验签成功后,还需校验事件类型、资产、用户归属和金额。webhook.test 仅用于验证连通性,不能据此给用户加款。为业务入账建立交易唯一约束,例如当前支持场景下使用资产与交易哈希组合,确保重复通知不会重复加款。
在同一个数据库事务中写入通知记录和业务账本。已处理过的有效通知直接返回成功;未完成落库时不要提前确认。
响应与重试
平台将任意 HTTP 2xx 视为投递成功,不要求特定响应正文。网络错误或非 2xx 响应会进入重试,间隔依次为 1、2、4、8 分钟,按指数增长,最高为 256 分钟。最多尝试 12 次,仍未成功则标记为失败。
在回调记录中可查看最近投递时间、响应状态码、响应正文与失败原因。修复接收端后,可以重新投递;正在投递或距离上次投递不足一分钟时不能手动重试。清空回调地址并保存会暂停投递。
回调成功代表商户服务已接收通知,不代表资金已归集到主钱包。归集和回调由不同任务处理。