概览

Webhooks

Docsbook 可以通知您的系统工作区内发生的事件 — 新内容已编入索引、需要翻译、有人提出聊天问题、流量异常 等。每个 webhook 都是有类型的:您可以订阅 18 个特定事件中的一个,而 Docsbook 仅在该确切事件触发时向您的 URL 发送 POST 请求。

注册 webhook 和接收其传送不会产生任何项目余额费用。您手动重放或测试的传送会按出站流量计费, 因为每一次传送都是 Docsbook 代表您发起的出站调用。

工作原理#

  1. 您使用 event_typeurl 和可选的 secret 注册 webhook。
  2. 事件发生时,Docsbook 会将一次投递加入队列(outbox 模式)。
  3. 工作程序(Vercel cron,每分钟运行一次)会将 JSON 正文 POST 到您的 URL。
  4. 我们会采用指数退避策略重试最多 3 次(1 秒、10 秒、60 秒)。

请求格式#

POST https://your-url.example.com
Content-Type: application/json
User-Agent: Docsbook-Webhooks/1.0
X-Docsbook-Event: content.indexed
X-Docsbook-Signature-256: sha256=<hex hmac of body>
X-Docsbook-Delivery: 12345
X-Docsbook-Attempt: 1
{
  "event": "content.indexed",
  "workspace_id": 42,
  "occurred_at": "2026-05-23T12:34:56.000Z",
  "data": { /* event-specific payload */ }
}

验证签名#

import crypto from "node:crypto"
const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(rawBody).digest("hex")
if (expected !== req.headers["x-docsbook-signature-256"]) reject()

2xx 响应 = 已交付。任何其他响应都会触发重试,直到尝试次数耗尽。

查看工作区发出的内容#

管理后台中的事件流面板会显示工作区产生的每个事件,最新的排在最前面 — 包括没有任何警报监视的事件,以及针对该工作区发起的每次 MCP 工具调用。无需注册 webhook 即可看到事件流 不断填充,这正是其意义所在:在决定要接收哪些通知之前,通过它了解文档实际发出了哪些事件。事件流是实时的 — 当你 查看它时会每隔几秒自动刷新,因此无需选择时间范围,也无需记得重新加载。

选择订阅源#

订阅源部分会打开一个卡片页面——每个订阅源对应一张卡片,每张卡片都有一行文字说明其 内容,末尾还有一张创建自己的订阅源卡片。打开卡片后会切换到该订阅源本身,上方没有标题或返回链接: 你是通过选择卡片来到这里的,而侧边栏中的订阅源行就是返回订阅源列表的方式。

相同的订阅源也会作为该侧边栏部分下的行显示,这样无需离开正在阅读的订阅源即可在它们之间切换——但该列表初始时是 关闭的。将鼠标悬停在订阅源行上,箭头会取代其图标;点击箭头即可显示最多五个订阅源,按最近打开时间 倒序排列,其余订阅源则通过再显示 N 个查看;下次回来时,Docsbook 会记住你是否让列表保持打开状态。用于从空筛选器 创建新列表的 + 同时位于该行上,也作为卡片显示在卡片库中。

系统内置了七个订阅源,因此你首次访问时,即使还没有保存任何内容,也有可以打开的项目:阅读者事件(阅读文档的用户所进行的所有操作—— 阅读的页面、执行的搜索、向 AI 提出的问题以及留下的反馈)、翻译(生成的每种语言,以及已过时或仍需生成的语言)、 语言事件(读者将文档切换到哪些语言)、聊天事件(向 AI 助手提出的问题、未能得到答案的问题以及收到差评的答案)、 读者反馈(页面或答案收到的差评和评论)、MCP 调用(代理发起的每一次计量调用),以及所有事件——未经筛选的全部事件。 所有事件排在列表最后,因为当其他命名订阅源都不适用时,你才会使用它。阅读者事件语言事件MCP 调用是用于阅读而非订阅的订阅源, 因为其中没有任何事件可附加提醒;另外四个则正是你可以指定通知器监控的内容。这七个订阅源都是起始筛选器,而不是已保存的列表, 因此无法删除,也不能直接将任何内容指向其中一个——缩小筛选范围并使用另存为列表,即可将其转换为你自己的订阅源; 它会作为独立的一行显示,也是提醒可以附加的形式。

阅读动态流#

动态流按天分段读取,每个项目占一行:当事件由某位读者触发时显示读者头像(计划、用量或 MCP 事件没有可归属的对象),显示代表其类型的彩色方块、事件名称、单行摘要以及事件的去向。状态、事件类型和目标以小图标显示,单击即可在弹出窗口中查看对应文字,因此整体内容始终保持一行。由于日期已由上方的分段标题标明,因此时间仅显示时刻。单击某一行可在原位置展开,显示完整事件——每次投递尝试及其响应、重放操作和原始负载。一个事件只有一个状态,该状态由其各次投递结果汇总而成,其中最差结果优先:

状态 含义
delivered 每个目标都已接受。
pending 已排队;工作线程尚未尝试处理。
retrying 某个目标拒绝了它,但仍在尝试次数限制内。
failed 某个目标拒绝了它,且尝试次数限制已耗尽。
not sent 事件已发生,但没有订阅该事件的警报。

信息流中的 MCP 工具调用#

信息流还会显示代理针对此工作区发起的每一次 MCP 工具调用,以及您的文档所分发的事件。每次调用占一行:调用的工具、是否成功、耗时,以及按 MCP 费率表上的标价计算的费用。失败的调用会明确标示。与任何一个项目都无关的调用——例如描述服务器、列出您的项目、创建项目——归属于您的账户,而不是某个项目,因此不会出现在任何项目的信息流中。

这些调用默认显示,无需开启任何设置。在添加事件选择器中,它们位于单独的MCP 调用部分,并按调用的计费类别进行筛选——mcp.readmcp.writemcp.querymcp.egressmcp.generatemcp.agent——而不是按工具名称筛选;计费类别才是产生费用的维度,也是随着新工具发布仍能持续适用的维度。每一行以及每个有效负载中都会显示工具自身的名称,因此只需搜索有效负载即可筛选出某个工具。免费调用(get_infofind_skillfind_widget以及其他发现类调用)永远不会计量,因此不会留下记录行。

工具调用从未被转发到任何地方,因此会显示为未发送;与读者活动一样,只要按目标或传送状态进行筛选,它就会立即从结果中消失。固定一个访客也会使其消失:持有令牌的代理不是您的读者,把它的调用算作某人的浏览行为是不正确的。

缩小动态流范围#

可按事件类型、状态、目标位置、访客、已完成的目标或负载中任意位置匹配的自由文本筛选动态流——筛选工具栏位于动态流上方的一行中,其上方没有标题。前五个筛选维度分别是图标按钮:悬停或聚焦即可查看其名称;设置后,按钮会填充为对应值,再次点击该值即可编辑。自由文本则是该行末尾始终可见的搜索框,而不是需要先打开的筛选维度。访客筛选只需从分析中点击一次即可使用——在那里打开某位访客的阅读者档案,就能直接查看他们完成的所有操作;也可以从动态流中某一行自身的头像点击一次进入,或手动粘贴 ID。固定某位阅读者后,动态流的搜索范围会扩大:除了文档分发的事件,还会提取该阅读者在网站上的活动——他们阅读过的页面、搜索过的内容以及提出的问题——因此,固定后的动态流展示的是该阅读者完成的所有操作,而不仅是可能触发提醒的部分。动态流上方还会显示一张卡片,说明该阅读者的身份:他们从哪里阅读、使用什么设备、系统和浏览器、阅读时使用的语言、反复访问的页面、累计阅读文档的时长、已达成的目标,以及他们当前的价值和未来可能产生的价值。该卡片仅适用于单个固定的阅读者,因为目标筛选对应的是一群人,而对一群人求平均得到的国家和浏览器并不能描述任何具体的人。保存筛选条件后,它会变成一个事件列表——因此,缩小动态流范围与定义要接收提醒的内容其实是同一个操作。测试 ping 会像其他事件一样出现在动态流中;重放会作为该事件下的另一次尝试显示。导出会将当前查看的内容原样下载,应用已设置的筛选条件且不受时间限制,格式可选 CSV、JSON 或 NDJSON——之所以不受时间限制,是因为动态流本身没有时间范围:它是实时的,而比所复制的视图范围更窄的文件还不如不提供文件。它位于同一工具栏行的末尾,紧邻设置提示设置提醒——这三个控件作用于整个视图,而不是单个事件。

让提示词在信息流上运行#

警报会将信息流中的事件转发给某个人。与它位于同一行的设置提示词会改为将这些事件交给您的助手:选择一个提示词后,每当有内容进入此信息流,它就会自动运行,无需任何人查看。按钮会显示数量,因此有内容的信息流不会看起来像没有内容的信息流;每个已启用的提示词都会显示在目标标签旁边的标签中——运行时为实心,暂停时为空心,工具提示中会显示其上次运行时间。

点击标签不会打开其设置,而是打开该提示词一直进行的对话:也就是该信息流上次发生变化时它实际执行内容的记录,位于助手的“触发器”组中。这是唯一能告诉您提示词确实在运行,而不只是处于启用状态的方式。

监视信息流时,监视的是已保存的信息流,因此您缩小范围但尚未保存的视图会对此作出提示,并指向另存为列表。您也可以从另一侧进行相同的启用操作——MCP 工具自身页面上的按计划或事件面板会在各个事件上方列出您的信息流;删除信息流会取消监视它的任何设置,而不会删除已启用的调用。

费用都花在哪了#

信息流中的每一行都带有价格,而单独的一行并不是任何人可以加总的列。 查看用量位于侧边栏的余额卡片上,点击后会将信息流替换为总额:在一段时间内,这个项目的钱花在了什么地方,按费用从高到低排列,分为三个部分。它不在信息流自己的工具栏中, 因为这个数字针对的是整个项目,而不是你正在查看的信息流。

部分 每行对应 数字代表什么
AI & tokens 服务和模型 每次 AI 回答、翻译或索引运行的定价
MCP tool calls 工具 该工具实际发起的调用的标价
Events logged 事件类型 按照费率表记录这些流量的成本

前两项是已计费的:这笔钱已从项目余额中扣除。第三项则未计费 — 事件被定价是为了让流量不会隐形,但不会因此扣款。因此,这两个总额会在两个不同的词语下分别显示为两个数字,并且每个部分都带有一个 chargednot charged 徽标,因为用一个数字涵盖三项,就会变成一张收取无人支付之款的账单。

选择 24 小时7 天30 天的时间范围。没有更长的选项,因为没有更长的内容可供读取:读者分析数据保留 30 天,AI 账本也会相应清理, 所以 90 天按钮实际上会在错误的标签下回答 30 天的数据。

这里的导出会将明细本身以 CSV 格式提供 — 每个模型、工具或事件类型一行,其中包含可作为普通数字求和的计数和费用,以及一列说明该行是否 已计费 — 同时还会提供其背后的原始事件,范围限定为你正在查看的时间窗口。

侧边栏的余额提示中点击查看用量打开的就是同一个页面 — 这张卡片会在项目余额不足时发出警告。充值位于账户菜单的余额区块中:前者回答 还剩多少余额,这里回答余额花在了什么地方。

通知器:事件的去向#

通知器是一个目的地——包括频道、频道 URL 及其凭据——它独立于所承载的事件而存在。您只需创建一次——在标题行中点击设置提醒,或在添加通知器底部点击新建通知器——然后将其勾选到它应服务的任意多个事件列表中。由三个列表提供事件的一个 Slack 频道就是一个通知器,使用一个签名密钥,可在一个位置暂停或删除。

当前所查看列表中已在触发的通知器,会以带标签的独立芯片形式显示在筛选芯片旁边——每个芯片都带有其频道的真实标记、名称,以及在关闭时显示的 paused。点击其中一个即可打开该通知器,这样您无需离开事件流,就能查看列表将事件发送到哪里并进行更改。在其他列表中触发的通知器——或尚未在任何列表中触发的通知器,因为每个新通知器都是从这里开始的——可通过添加通知器菜单访问,该菜单中的每一行复选框旁边都有编辑控件。

取消勾选某个列表后,通知器将不再在该列表上触发;取消勾选最后一个列表后,目的地仍会保留,但不再附加到任何列表,也不会传送任何内容,直到您再次为其指定位置。删除事件列表也会对曾在其上触发的任何通知器执行同样的处理——列表丢失不会使订阅范围扩大。

只有已保存的列表才能接收通知:内置事件流(包括所有事件)是筛选器而非列表,因此请先将所需内容保存为您自己的事件流。

事件目录#

Docsbook 工作区会发出 18 种类型化事件。下面每一行都列出了事件在 X-Docsbook-Event 标头和正文的 event 字段中出现的确切名称,以及其 data 对象所携带的字段。

事件 负载字段
content.indexed pages_count, relations_count, indexed_at
content.outdated (已弃用 — 不再自动触发) last_indexed_at, repo_head_sha
translation.needed source_path, language
translation.completed source_path, language, origin
translation.outdated source_path, language, source_hash_changed
chat.question_asked question, answered, chat_id
chat.no_answer question, chat_id
chat.negative_feedback chat_id, question, answer
search.no_results query
search.popular query, count_24h
traffic.spike (高级事件) path, views, baseline
traffic.drop (高级事件) path, views, baseline
feedback.received path, rating, comment
plan.upgraded from, to
plan.downgraded from, to
usage.limit_approaching metric (ai|translation), used, limit
usage.overage_limit_reached workspace_id, overage_spent_cents, overage_limit_cents
mcp.tool_called (高级事件) tool_name, args

十八种事件中有三种标记为高级traffic.spiketraffic.dropmcp.tool_called。每一种事件都源自基线或计量活动,而不是由单个操作直接触发。

注册 Webhook#

通过 REST#

curl -X POST https://docsbook.io/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{"workspace_id": 42, "event_type": "content.indexed", "url": "https://you.example.com/hook"}'

响应中恰好包含一次 secret — 请将其保存。

event_type 接受事件名称的两种拼写形式:本页面通篇使用的点号形式(content.indexed)或下划线形式(content_indexed)。两者注册的是同一个订阅。

可选的 Authorization 标头#

某些接收方(例如 Claude Code 例程触发 URL)要求每个请求都携带其专用的 Bearer 令牌,这与 HMAC 签名验证分开。创建 Webhook 时传入 auth_header,Docsbook 会在每次发送时将其原样作为 Authorization 标头发送:

curl -X POST https://docsbook.io/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{"workspace_id": 42, "event_type": "content.indexed", "url": "https://you.example.com/hook", "auth_header": "Bearer sk-..."}'

如果该值不包含空格,则会将其作为 Bearer <value> 发送;如果它已经包含 方案(例如 Bearer sk-...),则会原样发送。

通过 MCP#

每个事件都有专用的 MCP 工具,因此 AI 代理可以订阅特定的通知流,而无需选择字符串:

register_webhook_content_indexed(workspace_id: 42, url: "https://YOUR_ENDPOINT")
register_webhook_translation_needed(repo: "owner/repo", url: "https://YOUR_ENDPOINT")
register_webhook_traffic_spike(workspace_id: 42, url: "https://YOUR_ENDPOINT")

其他 MCP 工具,以及每次调用所计入的计费类别:

工具 计费 功能
list_webhooks(workspace_id) 读取 列出工作区中注册的 Webhook
unregister_webhook(webhook_id) 写入 移除一个订阅
test_webhook(webhook_id) 出站 向已注册的 URL 加入一个合成 ping
list_webhook_deliveries(webhook_id) 分析 包含状态、重试次数和负载的投递历史
replay_webhook_delivery(delivery_id) 出站 重新投递一次过往的投递

REST 端点#

  • GET /api/webhooks?workspace_id=X — 列出
  • POST /api/webhooks — 创建
  • PATCH /api/webhooks/:id — 重命名、暂停/恢复,或重新指向另一个事件列表
  • POST /api/webhooks/:id/attach{ "list_id": N },从同一目标(相同 URL、相同密钥)提供另一个列表
  • DELETE /api/webhooks/:id — 删除
  • POST /api/webhooks/:id/test — 测试 ping
  • GET /api/webhooks/:id/deliveries — 最近的传送记录
  • POST /api/webhook-deliveries/:id/replay — 将现有传送重新加入队列

重试和失败语义#

  • Worker 通过 Vercel cron 每分钟运行一次。
  • 每次传递最多尝试 3 次。
  • 根据该行的 created_at 实施退避:1 秒、10 秒、60 秒。
  • 第 3 次失败后 → status = "failed"。使用 replay_webhook_delivery 重新尝试。
  • 每次传递都会在对应的传递行中存储响应代码和(截断后的)正文。

Updated

此页面对您有帮助吗?