签署 webhook
公开目录恰好包含五种事件:
| 类型 | data 附加字段 |
|---|---|
partner.ping | 控制台测试 payload |
signing_request.completed | 终态 status |
signing_request.declined | 终态 status |
signing_request.item.signed | signingRequestItemId、documentKind、signedAt、sessionStatus |
signing_request.cancelled | 终态 status |
每个 envelope 都有 id、type、dataVersion(2026-09-01)、occurredAt 和精简 data。签署 data 总含十进制字符串 groupId、signingRequestId、contactId,绝不包含 token、原因、哈希、邮箱、IP、user agent、URL 或文件内容。item 事件刻意使用 sessionStatus,不是终态 status。
投递携带 X-Sx-Webhook-Timestamp、X-Sx-Webhook-Signature、X-Sx-Webhook-Event-Id。用 <timestamp>.<原始 body 字节> 验证,执行 ±300 秒检查,并尝试所有签名。v1=<base64> 为 HMAC-SHA256;v2=<key-id>:<base64> 为 RSA SHA256/PKCS#1 v1.5。轮换或算法迁移期间最多两个签名。RSA key id 只用于选择候选公钥,绝不是验证证据。按事件 id 去重。
收到后应先持久记录,再返回 2xx;即使验签失败也应记录并排查,因为 4xx 会被视为永久失败。投递是至少一次且重试有界,不保证顺序或 exactly-once。
P6 已将生产与消费分离。Partner API 和 Academy 的所有模式(WEB、CRON、ALL)都仅生产队列任务;同时运行的 PARTNER_ROLE=worker 进程是 partner-webhook 队列处理器和 15 秒恢复扫描的唯一所有者,并通过同一个 producer 重新入队恢复行。worker 只暴露内部 GET /health,绝不暴露 /v1 或 Academy 管理路由。API 与 worker 使用同一 Redis endpoint 和 BullMQ 默认 bull prefix。worker 隔离无法消除的永久捕获限制见对账。