加密支付 Webhook:事件、安全与可靠的订单履约

Webhook 是你的商店得知一笔加密付款已最终确认的时刻。本文介绍如何设计安全、幂等、稳定可靠的处理程序,并附事件对照表和上线检查清单。

更新于: 阅读约 4 分钟
加密支付 Webhook——签名的账单事件从支付网关发往商家服务器

加密支付 Webhook是支付网关在账单状态每次变化时发送到你服务器的 HTTP 请求:转账已检测到、链上已确认、少付、多付或已过期。你的处理程序校验签名、更新订单并触发履约。由于加密付款是异步到达的——往往在客户离开页面几分钟之后——真正可信的依据是 Webhook,而不是浏览器。

本文聚焦集成中的 Webhook 部分:会收到哪些事件、如何校验、同一事件到达两次时如何安全处理,以及如何测试和监控。创建账单请参阅加密支付 API 集成指南。

为什么用 Webhook,而不是轮询或跳转?

  • 跳转不是证据——客户回到“感谢”页面,并不能说明钱已到账。
  • 轮询很浪费——每隔几秒就为每张未完成账单调用 API,无法扩展而且仍有延迟。
  • Webhook 是推送——一有变化网关就会通知你,并附带可校验的签名。
要点:绝不要因为跳转、聊天消息或截图就把订单标记为已付。只有经过校验的 Webhook(或经过认证的 API 状态查询)才算数。

你会收到的事件

事件含义处理程序应做什么
invoice.paid已检测到转账,等待确认显示“已收到付款,确认中”;暂不发货
invoice.confirmed已达到所需确认数标记已付并履约
invoice.underpaid少于应付金额,低于容差告知客户差额,等待补款
invoice.overpaid到账多于应付正常履约,并决定如何处理差额
invoice.expired期限内无有效付款释放预留库存,订单保持未付

以上是 mistKET 使用的事件名称。其他网关的状态类似但名称不同,请在一个地方统一映射到你的订单状态。

校验签名

任何人都可以向公开 URL 发送 POST 请求,因此每个 Webhook 都必须验证身份。mistKET 用 HMAC-SHA256 对每次投递签名,并发送以下请求头:

  • X-Mistket-Event——事件名称。
  • X-Mistket-Timestamp——参与签名的 Unix 时间戳。
  • X-Mistket-Signature——sha256= 加上用你的 Webhook 密钥对 {timestamp}.{raw body} 计算的 HMAC。
  • X-Mistket-Delivery——用于日志记录的投递 ID。
  1. 读取原始请求体——在解析 JSON 之前读取,因为重新编码会改变字节。
  2. 重新计算 HMAC——对时间戳、一个点号和原始请求体,使用 Webhook 密钥计算。
  3. 常量时间比较——使用 hash_equals、hmac.compare_digest 或 crypto.timingSafeEqual。
  4. 拒绝过旧的时间戳——例如超过五分钟,以防重放攻击。
  5. 然后再解析和处理——并尽快返回 2xx。

该机制遵循标准 HMAC 模式;密钥只保存在服务器上,一旦泄露立即轮换。

选择并保护回调 URL

使用独立的 HTTPS 路径,例如 /webhooks/mistket,与普通页面分开,并在创建每张账单时作为回调 URL 传入。把它排除在 CSRF 防护、缓存和跳转之外:301 跳转或缓存响应是 Webhook 静默失败的常见原因。不要要求会话 Cookie——网关不是已登录用户,HMAC 签名才是身份验证。最后,为每次投递记录事件、订单号和响应码,这样几秒钟就能回答“Webhook 到了吗?”。

幂等性:同一事件可能到达两次

如果你的接口超时或返回错误,网关会在数小时内以递增间隔重试。网络抖动也可能重复投递你已处理过的事件。因此处理程序必须是幂等的:

  • 以订单号为键——找到账单关联的订单。
  • 检查当前状态——若订单已履约,直接确认收到,不做其他操作。
  • 使用事务或锁——防止两次并行投递都发货。
  • 保存投递 ID——便于排查重复投递。
提示:事件校验并保存后立即返回 200,把发送邮件、开通服务器等耗时操作放到后台任务。处理慢会导致超时,超时又会引发重试。

围绕事件设计订单状态

一个简单的状态机就能避免大多数问题:待付款 → 确认中(收到 paid)→ 已付款(收到 confirmed)→ 已履约,另有 少付 和 已过期 分支。只允许向前流转:在 invoice.confirmed 之后到达的 invoice.paid 绝不能让订单回退。过期账单上的延迟付款应生成待审核记录,而不是悄悄重新打开订单。

处理棘手情况

  • 少付——准确告知客户还差多少,并说明可在同一付款页面补齐;部分付款会累计。
  • 多付——正常履约,再按你的政策决定计入余额还是转账退款。
  • 过期——释放库存,若客户仍想购买,提供新账单。
  • 网络错误——由客服而非代码处理;在收银页清楚标明网络即可预防。
安全提醒:绝不要把 API 或 Webhook 密钥放在前端代码、移动应用或聊天机器人的消息逻辑里。密钥只保存在服务器上,用 IP 白名单限制 API 访问,并在商家后台启用双重验证。

测试与监控

  1. 开放测试接口——通过 HTTPS,记录请求头和原始请求体。
  2. 触发每种事件——用小额真实付款触发 paid、confirmed、underpaid、overpaid 和 expired。
  3. 重放一次投递——确认处理程序会忽略重复事件。
  4. 破坏签名——改动一个字节,确认请求被拒绝。
  5. 查看投递日志——商家后台会显示每次尝试、响应码和交易哈希。
  6. 失败告警——非 2xx 响应激增意味着订单没有被履约。

机器人和付费社群遵循同样的模式;在在 Telegram 机器人中接受加密付款一文中可以看到它如何融入聊天流程。

mistKET 的 Webhook

mistKET 为每种账单状态发送 HMAC 签名的 Webhook,对失败的投递按递增间隔重试,并在商家后台显示投递日志、应收与实收金额以及交易哈希。API 请求也以同样方式签名,一个辅助函数即可覆盖双向。

5种账单事件
HMACSHA-256 签名
数小时自动重试

在开发者专区查看请求和 Webhook 示例,了解价格,并通过商家登录管理密钥。如需接入,请通过 Telegram @mistnetwork 申请。

常见问题

什么是加密支付 Webhook?
账单状态每次变化(如检测到付款、已确认、少付或过期)时,网关发送到你服务器的 HTTP 请求。
应该由哪个事件触发订单履约?
达到所需链上确认后的 confirmed 事件。paid 事件仅表示已检测到转账。
如何校验 mistKET 的 Webhook?
用 Webhook 密钥对时间戳、点号和原始请求体重新计算 HMAC-SHA256,与 X-Mistket-Signature 进行常量时间比较,并拒绝过旧的时间戳。
为什么同一个 Webhook 收到了两次?
当你的接口超时或出错时,投递会被重试。请在履约前检查订单状态,让处理程序保持幂等。
如果我的服务器宕机怎么办?
Webhook 会在数小时内以递增间隔重试,你也随时可以通过 API 或商家后台查询账单状态。

相关文章