跳转到内容

Webhook 规范

了解 Tracksuite 在 Webhook 中发送的事件和运单字段,以及如何用签名密钥验证请求。

请求体是一个 JSON 数组,一次可以包含多条运单更新。每条更新用 event 表示发生了什么,这个名字由运单当前的 status 决定。对应关系见下表。status 与 statusLabel 的含义见运单状态。

每条更新都有 eventId、eventTime 和 data。同一条更新被重试时,eventId 不变,接收端用它去掉重复。data 是这条运单当时的内容:运单号 trackingNumber、状态 status、承运商细分状态 statusTrack、运单编号 routerId、当前摘要 summary、轨迹 detail。承运商返回了错误对象时,data 里还会多一个 error。

Tracksuite 发出的每个 Webhook 都带有计算好的数字签名。你的服务器可以用它确认请求来自 Tracksuite。没有签名密钥的第三方或恶意请求无法通过校验。签名使用 SHA256 对原始请求体计算 HMAC,结果是十六进制字符串,放在请求头 X-Tracky-Signature 里。

登录 Tracksuite 管理门户,打开 设置 → API 与 Webhook,复制签名密钥。接收地址和签名密钥都有值之后,Tracksuite 才会开始投递。

用签名密钥对收到的原始请求体做 HMAC-SHA256,输出十六进制字符串。计算时必须用这一段原始字符串。不要先解析 JSON 再重新序列化,也不要对 X-Tracky-Timestamp 计算,否则签名会对不上。

取出请求头 X-Tracky-Signature,和上面算出的结果比较。下面这个函数先计算,再比较。返回 false,或请求头缺失时,返回 401,拒绝这次请求。验证通过后,先在 5 秒内返回 2xx,再处理较慢的业务。

import { createHmac, timingSafeEqual } from 'node:crypto'
function verifySignature(rawBody: string, signature: string): boolean {
const expected = createHmac('sha256', WEBHOOK_SECRET).update(rawBody).digest('hex')
if (expected.length !== signature.length) {
return false
}
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}