收不到 webhook,或验签失败
排查 webhook 投递丢失与签名验证错误的检查清单。
webhook 问题大多落在两类:投递根本没到达你的服务器,或到达了但验签失败。请按下面对应的清单逐条排查。
投递没有到达
-
该端点订阅了这个事件所在的分组吗? 在控制台里订阅是按分组而非单个事件选择的,共三类:支付事件(
payment_order.*、payment.*)、商家订阅事件(end_user_subscription.*、end_user_invoice.*)与运维事件(address.pool.low以及agent.action.*审批)。只订阅了支付事件的端点不会收到订阅类或运维/Agent 事件,反之亦然。三类都不勾是不允许的;三类都勾表示“全部事件”,含将来新增的类型。(API 的enabled_events字段技术上可携带任意子集,但控制台的分组模型无法表达任意子集。在控制台保存一个自定义子集会把它扩成整组。) -
你的服务器是否在 10 秒内返回了
2xx? 任何非2xx状态、网络错误,或 10 秒内无响应都算失败。处理函数在响应前就做了大量实际工作是常见原因。先返回200,再异步处理。 -
查看投递日志。 每次尝试都会记录
response_status、response_duration_ms、error_message、attempts、next_retry_at以及status(pending/succeeded/failed/dead_letter)。这通常能立刻看出问题是否出在你这一侧。 -
把重试也算进去。 失败的投递按下面的曲线重试,到第 6 次进入死信队列:
尝试次数 延迟 1 30 秒 2 60 秒 3 5 分钟 4 30 分钟 5 2 小时 6+ 死信队列 -
修复后重放。 重放接口(以及面板上的重放按钮)会入队一条全新的投递记录,原始审计日志会被保留。用 replay-dead-letters 排空在你的端点宕机期间落入死信队列的投递。
验签失败
-
针对原始 body 验签。 在任何 JSON 解析或重新序列化之前,对你收到的精确字节计算签名。会先解析再 re-stringify body 的框架会改变它从而破坏签名。这是最常见的单一原因。
-
从正确的请求头读取签名。 使用 SDK 的
SIGNATURE_HEADER常量,而不要硬编码字段名。 -
使用正确的 secret。
secret仅在创建和轮换时返回。如果没存下来,轮换一次拿新的。 -
轮换期间同时接受两个 secret。 轮换后,旧 secret 会与新 secret 并存有效 24 小时。把两者都传给验签器,让灰度过程中在途的投递不会失败:
import { SIGNATURE_HEADER, verifySignature } from '@stableops/api-sdk/webhooks' const result = verifySignature({ secrets: [currentSecret, previousSecret], // 24 小时重叠期内两者都有效 header: request.headers.get(SIGNATURE_HEADER) ?? undefined, rawBody, }) if (!result.ok) { console.error('Invalid signature:', result.reason) // 拒绝该请求 }
相关
这篇文档怎么样?
最后更新