指南
Webhooks
接收批量任务完成通知
对于运行时间超过一分钟的批量任务,Webhook 比轮询更便宜也更快。当任务到达终态时,Thunderbit 会向你的 URL 发起 POST。
提交时配置
{
"urls": ["https://example.com/page1"],
"webhook": {
"url": "https://your-server.com/api/webhook/distill",
"secret": "whsec_your_secret_key",
"headers": { "X-Custom-Auth": "your-token" }
}
}webhook.headers 字段接受自定义请求头映射,但该字段为预留字段,服务端目前尚未发送。请仅按照下方文档列出的请求头进行验签。
请求头
每次投递都会包含以下 4 个请求头:
| Header | Value |
|---|---|
Content-Type | application/json |
X-Webhook-Event | batch.completed |
X-Webhook-Timestamp | Unix 时间戳(毫秒) |
X-Webhook-Signature | sha256=<base64-encoded HMAC-SHA256> |
载荷
{
"id": "batch_a1b2c3d4...",
"jobType": "batch_distill",
"status": "COMPLETED",
"total": 50,
"completed": 49,
"failed": 1,
"creditsUsed": 100,
"createdAt": "2026-04-26T10:00:00Z",
"completedAt": "2026-04-26T10:05:23Z"
}jobType取值为batch_distill或batch_extract。status取值为COMPLETED、FAILED或CANCELLED。
载荷有意保持精简——收到回调后请通过 GET /batch/distill/{id}(或 /batch/extract/{id})拉取完整结果。
签名校验
设置了 secret 后,每次投递都会带上 X-Webhook-Signature 请求头。
- 算法:HMAC-SHA256
- 待签名字符串:
<X-Webhook-Timestamp>.<raw-json-body>(两者之间是一个字面意义的.) - 输出格式:
sha256=<base64-encoded-hash>(Base64,不是 hex)
请使用原始请求字节进行校验(不要重新序列化 JSON),然后做恒定时间比较。
import hmac, hashlib, base64
def verify(raw_body: bytes, timestamp: str, signature: str, secret: str) -> bool:
base = f"{timestamp}.{raw_body.decode('utf-8')}".encode('utf-8')
digest = hmac.new(secret.encode('utf-8'), base, hashlib.sha256).digest()
expected = "sha256=" + base64.b64encode(digest).decode('ascii')
return hmac.compare_digest(expected, signature)重放保护
如果 |now - X-Webhook-Timestamp| > 60000(60 秒窗口),请拒绝该请求。时间戳为 毫秒 Unix 时间戳。生产环境绝不要信任未签名的 webhook。
重试行为
- 单次投递超时:30 秒
- 最大重试次数:3
- 退避策略:指数退避,起始 1 秒,上限 10 秒
- 端到端总窗口:约 120 秒
所有重试都失败后,任务在我们这边仍是已完成状态——你的接收端必须是幂等的(建议以 id 作为去重键)。