Webhook 测试器

生成带签名的 BoltUtil Webhook 测试载荷

创建真实感 Webhook body,计算 HMAC-SHA256 签名,并复制可用于本地或预发环境的 cURL 命令。

检查项

原始 body 签名

检查项

HMAC-SHA256

检查项

可用 cURL

签名工作台

使用:HMAC_SHA256(timestamp + "." + rawBody, secret)

签名

9bb63da06ffb56bfd65d1eeb07c37ca52b895c13f1c377e472ac3e0b123a6faa

Body 状态

JSON body 有效

生成的请求

将该请求发送到你的 Webhook 接口。服务端应基于原始请求 body 验证签名,并且只在安全记录事件后返回 HTTP 2xx。

curl -X POST "https://merchant.example.com/webhooks/boltutil" \
  -H "Content-Type: application/json" \
  -H "X-Bolt-Webhook-Timestamp: 1784826915691" \
  -H "X-Bolt-Webhook-Signature: 9bb63da06ffb56bfd65d1eeb07c37ca52b895c13f1c377e472ac3e0b123a6faa" \
  --data '{
  "externalOrderId": "ORDER_2026_001",
  "status": "CONFIRMED",
  "amount": "199.000000",
  "currency": "USDT",
  "network": "TRC20",
  "txHash": "0x1abd1849cf65896b103d3a252849f9460fc45d86cb1031c9c36c0205b0a2913c",
  "confirmations": 20,
  "destinationAddress": "TMerchantSettlementWallet",
  "paidAt": "2026-05-25 12:30:00",
  "confirmedAt": "2026-05-25 12:35:00",
  "metadata": {
    "plan": "pro",
    "userId": "u_123"
  }
}'

01

验证原始 body

在 JSON 解析器改变格式或 key 顺序前,基于完整原始请求 body 字节计算 HMAC。

02

使用恒定时间比较

使用语言运行时提供的 constant-time 工具比较收到的签名和计算结果。

03

持久化后返回 2xx

只有在记录事件或写入可靠内部队列后,才返回成功。

Webhook 排查

为什么支付 Webhook 可能失败

大多数 Webhook 问题来自签名验证、body 解析、重试处理,或在系统安全记录支付事件前就返回成功。

签名不匹配

最常见原因是对解析后的 JSON 签名,而不是精确原始 body,或使用了与请求头不同的时间戳。

密钥错误

请使用商户回调地址配置的 Webhook 密钥。API Key 和 Webhook Secret 应视为不同凭证。

Body 解析器改变了载荷

JSON 中间件可能重排或格式化 payload。校验 HMAC 前应先捕获原始 body。

接口返回非 2xx

BoltUtil 会把非 2xx 响应视为投递失败,并按配置的重试策略继续重试。

处理逻辑不幂等

Webhook 重试可能多次投递同一事件。请保存事件 ID 或交易哈希,避免重复履约。

持久化前返回成功

只有在事件写入数据库或队列后才返回 HTTP 2xx,否则服务崩溃可能丢失已完成支付通知。

常见问题

Webhook 调试问题

当支付已完成但应用没有按预期更新时,可以按这些检查项排查。

为什么 Webhook 签名校验失败?

请验证精确原始请求 body、时间戳请求头和配置的 Webhook 密钥。对解析后的 JSON 或重新格式化后的 body 签名通常会得到不同 HMAC。

Webhook 接口必须在响应体返回 SUCCESS 吗?

正常 HTTP 2xx 才是最重要的投递成功信号。接口可以返回简单 JSON,但投递系统应该依赖状态码判断成功。

如何处理重复 Webhook 投递?

让处理器保持幂等。在履约前保存唯一事件 ID、订单 ID 加状态,或交易哈希,然后安全忽略重复事件。

什么时候应该返回 HTTP 2xx?

只有在支付事件被安全记录或进入队列后才返回 2xx。如果校验失败或无法持久化事件,请返回非 2xx 以便重试。