接收项目通知
配置接收服务、验证通知,并在 CaptionBolt 项目变化时测试工作流。
准备接收服务
视频可供检查、导出完成、处理失败或项目取消时,Webhooks 会向应用发送 HTTP 请求。集成能力向 Max 订阅用户开放。
需要接受 POST 的公共 HTTPS URL,仅支持 443 端口。localhost 和私有网络地址无法直接接收,CaptionBolt 不跟随重定向。本地测试可通过公共 HTTPS 隧道连接接收服务。
示例使用 https://receiver.example/captionbolt,请替换为实际接收地址。
添加接收地址
- 打开设置 → 集成。
- 填写 HTTPS 接收地址 并选择事件。
- 点击 添加 Webhook。
- 保存显示的签名密钥,它只显示一次。
接收服务用此密钥验证通知;它与 API Key 是不同的密钥。
也可通过 REST 创建地址。按 API 指南将 CAPTIONBOLT_API_KEY 设置为拥有 webhooks:manage 权限的密钥:
curl --fail-with-body https://api.captionbolt.com/v1/webhooks \
-H "Authorization: Bearer $CAPTIONBOLT_API_KEY" \
-H 'Content-Type: application/json' \
--data '{"url":"https://receiver.example/captionbolt","events":["project.completed","project.failed"]}'
响应返回接收地址的 id 和签名 secret。将密钥安全地存入接收服务环境。
选择事件
| 事件 | 含义 |
| --- | --- |
| project.ready | 视频处理完成,可供检查或导出 |
| project.completed | 导出完成,可获取结果;默认选中 |
| project.failed | 处理或导出失败;默认选中 |
| project.cancelled | 项目已取消 |
事件覆盖账户中符合条件的视频项目,无论通过网站、REST 或 MCP 创建。新地址只接收之后发生的事件,不重放之前的项目变化。不包含独立 Transcripts、已删除或超出访问期的项目。
project.ready 不表示视频已导出,也不表示用户已人工检查。
{
"id": "event-uuid",
"type": "project.completed",
"createdAt": "2026-09-27T12:00:00.000Z",
"data": {
"projectId": "project-uuid",
"status": "completed",
"stage": "export",
"resultUrl": "https://api.captionbolt.com/v1/projects/project-uuid/result"
}
}
事件只含元数据,不含视频文件或字幕文本。data.resultUrl 是需要鉴权的 REST 端点。用具有 projects:read 的 API Key 获取新下载链接,再下载文件;下载文件时不发送密钥。参见下载结果。
验证收到的请求
CaptionBolt 使用 Standard Webhooks。解析或处理前,针对未经修改的原始请求体验证签名。请求头为 webhook-id、webhook-timestamp 和 webhook-signature。
Node.js 接收服务示例
此最小示例验证签名并打印事件 ID 和类型,供测试投递。示例使用 Node.js 24,接收服务也可用其他语言实现。在自己的接收服务项目中安装 JavaScript 验证库:
npm install standardwebhooks
read -r -s -p 'CaptionBolt signing secret: ' CAPTIONBOLT_WEBHOOK_SECRET
export CAPTIONBOLT_WEBHOOK_SECRET
printf '\n'
保存以下代码为 receiver.mjs:
import { createServer } from "node:http";
import { Webhook } from "standardwebhooks";
const secret = process.env.CAPTIONBOLT_WEBHOOK_SECRET;
if (!secret) throw new Error("Set CAPTIONBOLT_WEBHOOK_SECRET.");
const verifier = new Webhook(secret);
createServer(async (request, response) => {
if (request.method !== "POST" || request.url !== "/captionbolt") {
response.writeHead(404).end();
return;
}
let event;
try {
const chunks = [];
let size = 0;
for await (const chunk of request) {
size += chunk.length;
if (size > 65536) {
response.writeHead(413).end();
return;
}
chunks.push(chunk);
}
const rawBody = Buffer.concat(chunks).toString("utf8");
event = verifier.verify(rawBody, {
"webhook-id": request.headers["webhook-id"],
"webhook-timestamp": request.headers["webhook-timestamp"],
"webhook-signature": request.headers["webhook-signature"],
});
} catch {
response.writeHead(400).end("Invalid webhook");
return;
}
console.log("Verified event:", event.id, event.type);
response.writeHead(204).end();
}).listen(3000, "127.0.0.1");
运行 node receiver.mjs,通过 HTTPS 服务或公共 HTTPS 隧道公开 /captionbolt。CaptionBolt 需访问公共 HTTPS URL,而非本地地址。
验证库检查签名和时间戳,需保持服务器时钟准确。验证前不要解析并重新序列化 JSON,也不要记录签名密钥或完整请求体。
生产工作流应将打印替换为持久化接收:按 id 去重,先保存事件或任务,再返回 2xx,并异步处理。持久化失败应返回错误,以便 CaptionBolt 重试。示例只验证接收,不提供持久化队列,也不下载结果。
发送测试
- 启动接收服务并配置签名密钥。
- 在设置 → 集成打开对应地址,选择 发送测试。
- 在投递记录中确认投递成功。
- 确认接收服务记录了通过验证的
webhook.test。
每个地址同时只能有一个测试。等待测试结束,再等至少 60 秒后发送下一个测试。手动重新投递也有冷却时间,请遵循返回的等待时间。
单独处理 webhook.test,它不代表视频完成。用之后发生的真实项目事件测试结果获取。
投递失败时,检查公共 URL、签名密钥、原始请求体处理和接收响应。需在 15 秒内确认接收;非 2xx、连接错误或无响应会触发重试。
处理重试和密钥变更
通知可能重复或乱序。按事件 ID 去重;工作流需要最新状态时,查询项目当前状态。
CaptionBolt 自动尝试三次:首次请求、首次失败约一分钟后重试、第二次失败约五分钟后再次重试。第三次失败后停止自动投递。修复接收服务后,在设置中选择 重新投递,保留事件 ID 并开始新一轮三次尝试。投递记录保留 30 天。
通过 轮换密钥 更换签名密钥。保存新密钥并更新接收服务。旧密钥在 24 小时内仍有效,期间投递包含新旧密钥的签名;重叠期结束前无法再次轮换。
停用地址会停止待投递任务,已发送中的请求可能完成。删除地址还会删除投递记录。删除项目或项目访问期结束,会停止待投递项目通知。Webhooks 不延长 14 天访问期,请在到期前获取并保存结果。