# General Translation Platform: Webhooks URL: https://generaltranslation.com/zh/docs/platform/orgs/webhooks.mdx --- title: Webhooks description: 当你的组织中发生事件时接收实时通知 --- 当你的组织中发生事件时,Webhooks 可让你的应用接收 HTTP POST 请求,例如翻译后的文件处理完成或翻译任务结束时。 Webhooks 仅适用于 **Team plan** 及以上套餐。 ## 设置 Webhook 1. 前往 **Organization Settings → Webhooks** 2. 点击 **Create Webhook** 3. 输入你希望接收事件的端点 URL (必须为 HTTPS) 4. 选择要订阅的事件类型 5. 点击 **Create** 创建端点后,前往 Webhook 详情页并复制签名密钥。你将使用此密钥来验证传入的请求是否来自 General Translation。 每个组织最多可创建 **5 个 Webhook 端点**。 ## 事件类型 | Event | Description | | --------------------------- | ---------------------- | | `translated_file.completed` | 翻译后的文件处理完成并可供下载时触发 | | `translated_file.edited` | 用户在翻译编辑器中手动编辑翻译后的文件时触发 | | `translation_job.completed` | 翻译任务完成时触发 | 每个端点都可以订阅一种或多种事件类型。你可以随时在 webhook 详情页更新订阅。 ## 负载格式 每次 webhook 投递都会通过 HTTP POST 发送,并附带 JSON 请求体: ```json { "id": "evt_xxx", "type": "translated_file.completed", "created_at": "2026-04-30T12:00:00.000Z", "api_version": "2026-03-06.v1", "data": { "object": { "id": "file_xxx", "org_id": "org_xxx", "project_id": "project_xxx", "branch_id": "branch_xxx", "source_file_id": "src_xxx", "file_id": "file_xxx", "version_id": "ver_xxx", "locale": "fr", "file_format": "json", "data_format": null, "completed_at": "2026-04-30T12:00:00.000Z" } } } ``` 顶层 `id` 是一个稳定的事件标识符,你可以用它在你的系统中对投递进行去重。 ## 验证签名 每个 webhook 请求都会包含 3 个用于签名验证的请求头: | 请求头 | 说明 | | ------------------- | --------------------- | | `webhook-id` | 事件 ID (`evt_xxx`) | | `webhook-timestamp` | 请求发送时的 Unix 时间戳 (秒) | | `webhook-signature` | `v1,` 签名 | 该签名遵循 [Standard Webhooks](https://www.standardwebhooks.com/) 约定。验证步骤如下: 1. 拼接:`{webhook-id}.{webhook-timestamp}.{raw request body}` 2. 使用你的签名密钥计算 HMAC-SHA256 (去掉 `whsec_` 前缀后,先对密钥进行 base64 解码) 3. 将结果进行 Base64 编码,并与签名值 (`v1,` 前缀之后的部分) 比较 4. 检查时间戳是否在当前时间的前后 5 分钟内,以防止重放攻击 ### 示例 (Node.js) ```js import crypto from "crypto"; function verifyWebhook(payload, headers, secret) { const msgId = headers["webhook-id"]; const timestamp = headers["webhook-timestamp"]; const signature = headers["webhook-signature"]; // 检查时间戳时效性(5 分钟容差) const now = Math.floor(Date.now() / 1000); if (Math.abs(now - parseInt(timestamp)) > 300) { throw new Error("Timestamp too old"); } // 计算预期签名 const signingKey = Buffer.from(secret.replace("whsec_", ""), "base64"); const signedContent = `${msgId}.${timestamp}.${payload}`; const expected = crypto .createHmac("sha256", signingKey) .update(signedContent) .digest("base64"); // 比较(常数时间) const received = signature.split(",")[1]; if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) { throw new Error("Invalid signature"); } return JSON.parse(payload); } ``` 你也可以使用适用于所用语言的 [Standard Webhooks](https://www.standardwebhooks.com/) 库,它会自动处理验证。 ## 重试与投递 Webhook 采用**至少一次投递**机制。如果你的端点未在 10 秒内返回 `2xx` 响应,系统会按指数退避策略重试,最多**10 次**。 你也可以在控制台的 Webhook 详情页手动重试失败的投递。 ### 处理重复事件 由于采用至少一次投递语义,你的端点可能会多次收到同一事件。请使用负载中的 `id` 字段进行去重: ```js app.post("/webhooks/gt", (req, res) => { const eventId = req.body.id; if (alreadyProcessed(eventId)) { return res.status(200).send("OK"); } // 处理事件... markProcessed(eventId); res.status(200).send("OK"); }); ``` ## 管理端点 在 Webhook 详情页中,你可以: * **启用/禁用** 端点,而无需将其删除 * **更新** 已订阅的事件类型 * **查看投递历史** 并检查每次投递尝试的详情 * **重试** 失败的投递 * **显示** 签名密钥 (便于重新复制) * **删除** 端点 ## 最佳实践 * **快速响应** — 尽快返回 `2xx` 响应,然后异步处理事件。运行时间过长的处理函数可能会超时。 * **验证签名** — 在信任负载内容之前,务必先验证 `webhook-signature` 请求头。 * **处理重复事件** — 存储已处理的事件 ID,并跳过重复事件。 * **使用 HTTPS** — 在生产环境中,webhook 端点必须使用 HTTPS。 * **监控失败情况** — 定期检查投递历史,查看是否存在持续失败的情况,这可能表明你的端点有问题。 ## 权限 管理 webhook 端点需要 `org:webhooks:write` 权限。查看投递历史需要 `org:webhooks:read` 权限。默认情况下,**Owner** 和 **Admin** 角色都具备这两项权限。详情请参阅 [角色与权限](/docs/platform/orgs/roles)。