跳转到主要内容

Webhook

Webhook 允许外部系统在 Kanera 中的工作变化时做出反应。

当另一个系统应该知道变更而不需要不断调用 API 时,使用 webhook。 常见示例包括:

  • 更新外部仪表板。
  • 同步更改的卡片到另一个系统。
  • 触发部署或审查工作流程。
  • 在审计系统中记录 Kanera 活动。

要将卡片活动发布到团队聊天通道中,您不需要自己的 webhook。 Kanera 内置了 聊天通知目标 为 Slack, Discord, Telegram, 并 Zulip 当你需要完整的事件目录、准确的有效载荷和签名验证时,可以使用 webhook。

工作区管理员可以从 工作区设置 -> API,在 自定义webhook 单独的板有相同的 API 集成还可以通过公共 API 或 TypeScript SDK 注册端点,并且可以在自身的板设置中注册端点。

显示 webhook 配置的 Workspace API 设置。

每个 webhook 目标都可以接收所有事件或仅接收选定的事件类型。 Leave eventTypes 空接收每个事件,或提供一个或多个事件类型字符串如下所示。

计划和权限​

  • 工作区管理员可以查看和管理该工作区中的每个通用 Webhook 端点。
  • 当端点的用户是工作区成员时,具有写入功能的 API 凭证或交互式 OAuth 代理可以在没有管理员权限的情况下注册端点。该端点的范围仅限于创建连接:只有相同的连接和工作区管理员才能查看或管理它。读取范围的凭据无法管理 Webhook。
  • 网络钩子需要 Pro 30天 Pro试用。它们在托管 Free 上不可用。
  • 在托管版 Free 套餐中,创建表单会替换为 您的计划中不提供 Webhook.

撤销凭据或代理连接还会删除其连接范围内的端点。 管理员创建的工作区端点保留,直到管理员删除它们。

降级时会发生什么​

当托管组织从 Pro 或试用版迁移到 Free 时,Kanera 会暂停每个启用的 webhook 端点,而不是删除任何内容。 它还会撤销工作区 API 密钥(私钥仍然有效 ), 并禁用超出 Free 限制的自动化。

主机上 Free行为
现有终点自动暂停,并且当组织处于 Free 状态时无法重新启用它们。
新活动未到达您的端点。
还有什么正在等待发送记录为失败 webhooks are unavailable on the current plan 而不是迟到。
交付失败无法手动重试。
配置和历史记录保留。 端点、事件选择、秘密和交付历史记录都仍然存在。

升级回 Pro 版本会重新启用因降级而暂停的端点,并恢复其撤销的工作区 API 密钥,因此无需重新构建恢复的集成。

通过编程注册端点​

公共 API 会公开 Workspace 设置所使用的相同通用端点生命周期。

/api/v1/workspaces/{workspaceId}/webhooks
方法路径使用
GET(基本路径)列出调用者可见的端点。
POST(基本路径)创建一个端点并返回其签名秘密一次。
PATCH/{endpointId}更改其名称、URL、事件过滤器或启用状态。
POST/{endpointId}/secret旋转签名秘密。
DELETE/{endpointId}删除端点。
GET/{endpointId}/deliveries阅读最近的交付尝试。
POST/{endpointId}/deliveries/{deliveryId}/retry重试一次失败的交付。

使用 TypeScript SDK,使用 kanera.webhookEndpoints.create(), .list(), .update(), .rotateSecret(), .deliveries(), .retryDelivery(), 和 .delete()。返回的端点有 scope: "workspace" 用于管理员管理的端点或 scope: "connection" 当非管理员凭据注册它时。 secret 通过创建或旋转立即返回;后续读取从不暴露它。

Webhook 事件类型​

公共 API 将当前列表公开于:

https://api.kanera.app/webhook-event-types
面积事件类型
列表list:created, list:updated, list:moved, list:rebalanced, list:deleted
板隔板separator:created, separator:updated, separator:moved, separator:rebalanced, separator:deleted
自定义字段customField:created, customField:updated, customField:moved, customField:rebalanced, customField:deleted
自定义字段选项customFieldOption:created, customFieldOption:updated, customFieldOption:moved, customFieldOption:rebalanced, customFieldOption:deleted
卡片card:created, card:updated, card:moved, card:rebalanced, card:deleted
卡片自定义字段card:customFieldValue:set, card:customFieldValue:cleared
卡片标签和受让人card:labels:set, card:assignees:set
卡片附件card:attachment:created, card:attachment:deleted
卡片清单card:checklist:created, card:checklist:updated, card:checklist:moved, card:checklist:rebalanced, card:checklist:deleted
卡清单项目card:checklistItem:created, card:checklistItem:updated, card:checklistItem:moved, card:checklistItem:rebalanced, card:checklistItem:deleted
工作区卡片标签cardLabel:created, cardLabel:updated, cardLabel:moved, cardLabel:rebalanced, cardLabel:deleted
评论意见comment:created, comment:updated, comment:deleted
评论反应comment:reaction:added, comment:reaction:removed
卡片进给card:feedItem:created, card:feedItem:updated, card:feedItem:deleted
看板board:created, board:updated, board:moved, board:rebalanced, board:deleted
看板成员board:member:added, board:member:removed
工作区workspace:updated, workspace:deleted
工作区成员workspace:member:added, workspace:member:updated, workspace:member:removed
用户user:profile:updated
笔记note:created, note:updated, note:moved, note:rebalanced, note:deleted, note:locked, note:unlocked
代理运行agentRun:started, agentRun:updated

有效载荷格式​

Kanera 将每个 webhook 作为 JSON 对象发送,具有稳定的信封和事件特定性 data.

外地意义
id唯一的 webhook 事件 ID。 X-Kanera-Event-Id.
type事件类型,如 card:created.
workspaceId事件发生的工作区。
boardId当事件属于看板范围时,事件发生的看板。
cardId当事件有效负载识别出卡时,卡参与事件。
occurredAt事件发生时的 ISO 8601 时间戳。
data形状取决于: type 并匹配相应的实时事件有效载荷。

代理运行的事件携带 { boardId, cardId, run } 在 data, 其中 run 是什么原因导致了这种情况? agentName, 的 userId 它为什么会这样做? status, title, summary, externalUrl,及其 startedAt, heartbeatAt, 和 endedAt 时间戳。 agentRun:updated 对于每一个心跳以及状态变化都会发射,所以请将您的处理器键入 run.status 一个停止心跳的运行作为最后一个步骤到达,而不是将每个交付作为新的工作。 agentRun:updated 与 status: "stalled".

例 子 card:created 有效载荷:

{
"id": "7e5c982a-e6c9-4ea7-9647-b14fe73ed50a",
"type": "card:created",
"workspaceId": "a069fd45-3bb3-4928-bac9-cb574a050d20",
"boardId": "48a52a55-763e-4c64-8a76-51ac56247f5c",
"cardId": "70c39cef-1aec-44e6-a8f5-f36f765a818d",
"occurredAt": "2026-05-28T12:34:56.000Z",
"data": {
"boardId": "48a52a55-763e-4c64-8a76-51ac56247f5c",
"card": {
"id": "70c39cef-1aec-44e6-a8f5-f36f765a818d",
"boardId": "48a52a55-763e-4c64-8a76-51ac56247f5c",
"listId": "3bb3c1b3-8fc7-4807-854d-2d5ff62df147",
"title": "Prepare kickoff agenda",
"position": "1000.0000000000"
}
}
}

网络钩传送​

Kanera 会以 JSON 形式发送 webhook 交付,并包含您可以用来验证请求的报头:

头条意义
X-Kanera-Event-Id唯一事件 ID。
X-Kanera-TimestampUnix 时间戳(秒 ) 。
X-Kanera-Signaturesha256= 加上一个 HMAC-SHA256 签名。

签名是根据以下因素计算的:

${timestamp}.${rawBody}

使用 webhook 端点秘密。

当端点返回非 2xx 状态或无法访问时,Webhook 交付将重试。 Kanera 记录交付历史记录,以便您可以查看失败、重试交付、暂停目标和从工作区 API 设置中轮换秘密。

验证 webhook 签名​

在信任有效载荷之前验证签名。

该 TypeScript SDK 为你做这件事,并且抛出而不是返回一个布尔值,这样处理器就不会忘记检查:

import { parseWebhook } from "@kanera/sdk";

app.post("/kanera/webhook", express.raw({ type: "application/json" }), async (req, res) => {
const event = await parseWebhook({
secret: process.env.KANERA_WEBHOOK_SECRET!,
payload: req.body, // the raw bytes
headers: req.headers,
});
// Handle event.type, event.workspaceId, event.boardId, event.cardId, and event.data.
res.sendStatus(204);
});

要自己验证,请比较以上的 HMAC {timestamp}.{body} 注意长度检查: crypto.timingSafeEqual 当两个缓冲区的长度不同时,攻击者会控制它们。

import crypto from "node:crypto";
import express from "express";

const app = express();

app.post("/kanera/webhook", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.header("X-Kanera-Timestamp") ?? "";
const signature = req.header("X-Kanera-Signature") ?? "";
const expected = "sha256=" + crypto
.createHmac("sha256", process.env.KANERA_WEBHOOK_SECRET!)
.update(`${timestamp}.${req.body.toString("utf8")}`)
.digest("hex");

const received = Buffer.from(signature);
const digest = Buffer.from(expected);
if (received.length !== digest.length || !crypto.timingSafeEqual(received, digest)) {
return res.status(401).send("invalid signature");
}

const event = JSON.parse(req.body.toString("utf8"));
// Handle event.type, event.workspaceId, event.boardId, event.cardId, and event.data.
res.sendStatus(204);
});

始终根据原始请求正文进行验证。如果您的框架在验证之前解析 JSON,则签名检查可能会失败或变得不可靠。

Kanera也发送 X-Kanera-Timestamp 以及 X-Kanera-Event-Id。拒绝时间戳超出现在几分钟时间的交付以绑定重播,并使用事件 ID 使处理程序幂等,因为交付可能会重试。

Webhook 是通用路径。 针对特定受众群体,有两种更狭窄的选项:

路径观众有效载荷设置位置订阅方案
Webhook另一个系统整个事件目录中已签名的 JSON工作区设置 -> APIPro或试用
聊天目的地团队频道格式化的消息,适用于 Slack、Discord、Telegram 或 Zulip工作区设置 -> 集成Pro或试用
个人交付渠道1人ntfy、Gotify 或已签名的 JSON 用于您自己的通知个人资料设置 -> 通知Pro或试用
MCP 活动订阅AI代理的主机签名卡和评论发生到回调代理人验证代理通过 MCP 订阅;无需在 Kanera 中设置每个计划

聊天目标与 Webhook 端点分开管理,并且不会出现在 Webhook 列表中,因此轮换 Webhook 机密绝不会影响聊天目标。

自动化的 调用网络钩子 行动是有针对性的,而不是基于订阅。 automation:webhook:called 只对规则中选择的端点执行,而不管该端点的普通 eventTypes 过滤器,同时保持相同的签名、重试和递送历史记录行为。 自动化.