接收 Webhook
新条目一保存就直接推送到您自己的地址。条目变为可检索(或未能变为可检索)、条目被删除,这两件事无法通过轮询得知,只能通过这条路径获得。接收地址在账户页面设置。
请求头
每次推送都会带上。是否校验由您决定。
| 请求头 | 示例 | 说明 |
|---|---|---|
webhook-id | msg_2KWPBg… | 幂等键。同一事件的所有重试中保持不变。 |
webhook-timestamp | 1614265330 | unix 秒。确认是近期值可防止重放。 |
webhook-signature | v1,g0hM9SsE… | 正文的 HMAC-SHA256,base64 编码。 |
content-type | application/json | 固定为该值。 |
| 您注册的认证请求头名称 | 您注册的认证请求头的值 | 若已注册则一并发送。 |
POST <your endpoint>
content-type: application/json
webhook-id: msg_2KWPBgLlAfxdpx2AI54pPJ85f4W
webhook-timestamp: 1614265330
webhook-signature: v1,g0hM9SsE+OTPJTGt/tmIKtSyZlE3uFJELVlNIOLJ1OE=
正文
信封始终一致,由 type 决定 data 的形状。
| type | data | 何时 |
|---|---|---|
note.created | 单个条目,包含正文 | 条目被保存时。并不表示已可检索 — 请看 status。 |
note.ready | { count, group_id?, items[] } | 已保存的条目变为可检索时。每一轮处理按分组各发一次。 |
note.failed | { count, group_id?, items[] } | 已保存的条目最终未能变为可检索时。条目仍然还在。 |
note.deleted | { count, items[{id}] } | 条目被删除时。只有 id——它们已经不在了。 |
webhook.ping | {} | 您点击测试连接时。 |
单条保存
{
"type": "note.created",
"timestamp": "2026-09-05T04:12:07Z",
"data": {
"id": 41,
"title": "…",
"summary": "…",
"content": "…",
"created_at": "2026-09-05T04:11:58Z",
"origin": "Claude",
"status": "ready",
"group_id": null
}
}
上传的一个分片
{
"type": "note.created",
"timestamp": "2026-09-05T04:12:09Z",
"data": {
"id": 42,
"title": "… (3/77, p.47–53)",
"summary": "…",
"content": "…",
"created_at": "2026-09-05T04:12:08Z",
"origin": "Upload",
"status": "pending",
"group_id": "9f2c1ab84e7d4f0b93c5a61d2e8b7c40"
}
}
上传的分片变为可检索时
{
"type": "note.ready",
"timestamp": "2026-09-05T04:31:12Z",
"data": {
"count": 2,
"group_id": "9f2c1ab84e7d4f0b93c5a61d2e8b7c40",
"items": [
{ "id": 42, "title": "… (3/77, p.47–53)", "status": "ready" },
{ "id": 43, "title": "… (4/77, p.54–60)", "status": "ready" }
]
}
}
上传的分片检索准备失败时
{
"type": "note.failed",
"timestamp": "2026-09-05T04:36:40Z",
"data": {
"count": 2,
"group_id": "9f2c1ab84e7d4f0b93c5a61d2e8b7c40",
"items": [
{ "id": 44, "title": "… (5/77, p.61–67)", "status": "failed" },
{ "id": 45, "title": "… (6/77, p.68–74)", "status": "failed" }
]
}
}
同一个文件可能一部分已就绪、一部分失败:这时两条事件会带着同一个 group_id,相隔几秒先后送达。
条目被删除时
{
"type": "note.deleted",
"timestamp": "2026-09-05T05:02:44Z",
"data": { "count": 2, "items": [{ "id": 42 }, { "id": 43 }] }
}
连接测试
{
"type": "webhook.ping",
"timestamp": "2026-09-05T05:10:00Z",
"data": {}
}
单条保存与上传
两种流程使用相同的事件类型;status 和 group_id 会告诉您收到的是哪一种。
单条保存——从 MCP、REST API 或仪表板保存时。只有一条 note.created,而且一到达就已经可以检索。
文件上传——文件会被拆成分片,每个分片各有一条 note.created。此时都还不能检索;准备好之后 note.ready 再单独发来。
| 单条保存 | 上传(一个文件) | |
|---|---|---|
note.created | 一条,status: "ready",group_id: null | 每个分片一条,status: "pending",带 group_id |
note.ready | 不会发送 | 分片变为可检索时发送 |
note.failed | 不会发送 | 某个分片无法变为可检索时发送 |
| 可检索时点 | note.created | note.ready |
| 可读取时点 | 立即 | 立即——等待的只是检索 |
| 分片编号 | — | 不是字段。只有标题里的 (3/77) 和 data.id 的顺序 |
status——表示条目是否可以检索。"ready"是可以,"pending"是还在准备中,"failed"是检索准备失败,检索不会找到它。group_id——一批条目的名字。它在您上传文件时签发,该文件的每个分片都带同一个值。它表示分片属于哪个文件,而不是第几个分片,也是把note.created和随后到来的note.ready关联起来的键。- 如果只需要能检索的条目——请以
note.ready为准,跳过status为"pending"的note.created。 - 待处理的分片也能立即读取——正文已经在负载里。如需再次读取,请用不计入打开次数的
GET /api/v1/notes/{id},整批则用GET /api/v1/notes/group/{group_id}。 note.ready不是每个文件一次——每次只带上同时准备好的分片,所以处理分批、或某个分片重试过,就会用同一个group_id发送多次。count是这一次带的条数,不是整个文件的分片数,请累加items。note.failed不表示条目被删除——它仍然保存着、也能读取,失败的只是检索准备。请不要从您的副本中删除它;删除另有自己的事件note.deleted。在仪表板点击重试可以重新准备,若再次失败会送来一条新的note.failed。
如何编写接收端
收到后立即返回 2xx,处理交给自己的队列。
| 要这样做 | 否则 |
|---|---|
立即返回 2xx,稍后处理 | 超过 25 秒我们会视为失败并重发。 |
用 webhook-id 去重 | 同一条目会被处理两次。 |
对重复返回 200,切勿 429 | 429 表示“慢一点”,我们会再发一次。 |
按 data.id 排序 | 重试可能超过后面的事件;顺序不保证。 |
| 注册最终地址 | 我们不跟随重定向——3xx 会当场结束投递。 |
验证签名(可选)
用于确认这次推送确实来自我们,且正文在途中没有被改动。
- 构造签名字符串:
{webhook-id}.{webhook-timestamp}.{原始正文} - 推导密钥:去掉密钥的
whsec_前缀,再对其余部分做 base64 解码 - 计算 HMAC-SHA256,base64 编码后与
v1,之后的值比较 - 检查
webhook-timestamp是否在当前时间的几分钟以内 - 用收到的原始字节校验——把 JSON 解析后再序列化会破坏签名
- 使用任意 Standard Webhooks 库(standardwebhooks.com)可代为完成第 1~5 步
签名密钥在账户页面,可在那里复制或更换。
重试
投递失败时我们最多再发三次(含首次共 4 次)。只有 2xx 算作送达。
| 响应 | 我们的处理 |
|---|---|
2xx | 完成。 |
408・429・5xx | 分别在 15 分钟、1 小时、3 小时后重试。 |
| 完全没有响应 | 按相同间隔重试。 |
3xx 及其他所有 4xx | 就此结束——答案不会改变。 |
即使持续失败,我们也不会自动停用投递。在此期间每天最多发一封邮件通知您,账户页面会显示连续失败次数和最后一次错误。
如果您的接收端停机超过约四小时,请用 GET /api/v1/notes/changes 追平。
更多
接收地址的设置、签名密钥和连接测试都在账户页面。REST API 的密钥、端点和错误见 REST API 文档。常见问题的答案在 FAQ 里。如果有不清楚或出问题 的地方,请联系我们——每一条消息都有真人阅读。