# Webhooks 分享相关事件发生时,PageDrop 会主动推送到你的 URL。每次投递都用 webhook 的密钥做 HMAC-SHA256 签名,接收方可以验证真实性。 ## 事件 | 事件 | 触发时机 | |---|---| | `share_visited` | 分享被成功渲染一次(每次访问都触发,不只是首次) | | `share_expiring_soon` | (预留)—— 将来由定时任务触发,目前未启用 | | `share_reported` | 有人对这个分享提交了一份举报 | 订阅方可以挑一部分事件订阅;投递是 best-effort 模式(超时 5 秒),每次都会写入 `WebhookDelivery` 审计日志。 ## 创建一个 webhook 只支持 session 鉴权(webhook 配置归控制台管,bot token 不能管理其它 token 或 webhook): ```bash curl -X POST $BASE/api/webhooks \ -b cookies.txt \ -H "Content-Type: application/json" \ -d '{"url":"https://your.app/pagedrop-hook","events":["share_visited","share_reported"]}' ``` 返回的 secret 只显示一次: ```json { "webhook": { "id": "cm...", "url": "...", "events": ["share_visited","share_reported"], "active": true, "createdAt": "..." }, "secret": "whsec_AbC...DeF" } ``` 请把 secret 存到安全的地方——之后无法再次读取(要轮换就先删除再重建)。 ## 请求形状 ```http POST /your-endpoint HTTP/1.1 Content-Type: application/json User-Agent: PageDrop-Webhook/1.0 X-PageDrop-Event: share_visited X-PageDrop-Signature: sha256= { "event": "share_visited", "timestamp": "2026-05-23T08:30:12.345Z", "data": { "shareId": "cm...", "token": "abcd1234", "fileId": "f_...", "fileName": "report.md", "fileKind": "MARKDOWN", "visitCount": 42, "uniqueVisitCount": 18, "ipPrefix": "203.0.113.0/24", "referer": "https://twitter.com/i/web/..." } } ``` ## 验证签名 ```js import crypto from 'node:crypto'; function verify(req, secret) { const sig = req.headers['x-pagedrop-signature']; const expected = 'sha256=' + crypto.createHmac('sha256', secret) .update(req.rawBody) // rawBody = 未解析的 UTF-8 请求体 .digest('hex'); return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)); } ``` `X-PageDrop-Signature` 缺失或不匹配的请求一律拒绝。 ## 列表与审计 ```bash # 列出你的所有 webhook curl -b cookies.txt $BASE/api/webhooks # 单个 webhook 的最近 50 次投递历史 curl -b cookies.txt $BASE/api/webhooks/{webhookId}/deliveries ``` 每条投递记录的字段:`{ event, status, responseCode, attempts, deliveredAt }`。 ## 限制 - 每个用户最多 10 个活跃 webhook。 - 每次投递超时 5 秒;不自动重试(每个事件只触发一次)。 - 投递日志保留每个 webhook 最近 50 次(更早的会被静默清理)。