核心指南
Webhook 管理 API
通过 Dashboard、API 或 MCP 配置任务通知,验证签名并排查投递失败。
Webhook 在异步任务完成、失败或超时时通知你的应用。可在 Dashboard → API → Webhooks、管理 API 或 TokenLab MCP 的 full 模式配置;三者使用同一工作区的端点和投递记录。
用哪个 Key
| 凭据 | 用途 | 使用位置 |
|---|---|---|
管理令牌 mt-… | 创建、读取、更新、删除、测试 Webhook,轮换签名密钥 | /v1/management/webhooks* 的 Authorization: Bearer mt-… |
模型 API Key sk-… | 调用模型、查询任务 | 模型 API 和 /v1/tasks/{id} |
签名密钥 whsec_… | 验证收到的通知来自 TokenLab | 你的回调接收服务,不作为 API Bearer Token |
在 Dashboard → API → Management Tokens 创建管理令牌,选择与提交模型任务的 API Key 相同的工作区。令牌只能访问所属工作区,不能跨工作区读取或修改 Webhook。sk-… 和 whsec_… 不能代替 mt-…。Dashboard 配置使用已登录的工作区管理员身份。
管理令牌与签名密钥只保存在后端,不放入前端代码、提示词、代码仓库或 URL。Management Token 还可调用其他工作区管理接口,并不是只拥有 Webhook 权限的专用令牌。
创建与管理
export TOKENLAB_MANAGEMENT_TOKEN="mt-your-management-token"
curl https://api.tokenlab.sh/v1/management/webhooks \
-H "Authorization: Bearer $TOKENLAB_MANAGEMENT_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"https://your-app.example/webhooks/tokenlab","events":["task.completed","task.failed","task.timeout"],"description":"生产任务通知"}'成功返回 201,包含端点 id 和仅显示一次的 secret(whsec_…)。立即安全保存;查询、列表、更新响应不包含签名密钥。每个工作区最多 10 个端点。URL 必须是公网 HTTPS,不能包含账号密码、查询参数或 fragment;不跟随重定向。
| 操作 | 接口 |
|---|---|
| 列表 / 创建 | GET / POST /v1/management/webhooks |
| 查询 / 更新 / 删除 | GET / PATCH / DELETE /v1/management/webhooks/{webhookId} |
| 轮换签名密钥 | POST /v1/management/webhooks/{webhookId}/rotate-secret |
| 发送测试 | POST /v1/management/webhooks/{webhookId}/test |
| 投递记录 | GET /v1/management/webhooks/{webhookId}/deliveries?page=1&limit=50 |
PATCH {"is_active":false} 暂停,PATCH {"is_active":true} 恢复并重置连续失败计数。轮换只返回一次新密钥,接收端应立即更新;正在发送的请求可能仍使用旧密钥,切换时可短暂同时接受新旧两把密钥。轮换不可撤销。
事件与载荷
订阅的是之后产生的异步任务终态事件,不补发历史事件,也不针对同步结果发送通知。同一工作区内符合事件类型的任务都会触发通知,用 data.taskId 关联创建响应的任务 ID。通知字段使用 camelCase,管理 API 响应使用 snake_case。
{
"id": "event-unique-id",
"type": "task.completed",
"created": 1790000000,
"data": {
"taskType": "video",
"taskId": "ldtask_0123456789abcdef0123456789abcdef",
"model": "your-selected-model",
"durationMs": 42000,
"resultUrls": ["https://your-result-url.example/video.mp4"],
"settledCost": 0.12
}
}| 事件 | data 字段 |
|---|---|
task.completed | taskType、taskId,可选 model、durationMs、resultUrls、settledCost |
task.failed | taskType、taskId、error、errorCode、retryable、refundOutcome |
task.timeout | taskType、taskId、expectedTimeoutMs、actualWaitMs、refundIssued、resolutionSource、refundOutcome |
webhook.test | 测试消息和订阅类型,仅测试操作发送 |
task.timeout 中的 expectedTimeoutMs 是超时阈值,actualWaitMs 是实际等待时间,单位均为毫秒。refundIssued: true 表示退款成功或此前已退款;false 不表示后续不会退款。refundOutcome 表示退款处理结果。超时事件不包含 durationMs。
字段依任务而定,可能缺省。使用原工作区的 sk-… 查询 GET /v1/tasks/{id},获取权威结果和计费状态。失败事件的 retryable 描述生成失败是否可重试,不表示应持续轮询终态任务,也不授权自动创建新的付费任务。task.failed 中的 error、errorCode 和 retryable 就是任务公开 error_details 的 message、code 和 retryable,与查询任务状态时返回的值一致。
先验签,再处理
请求头包含 X-Webhook-ID、X-Webhook-Timestamp(Unix 秒)和 X-Webhook-Signature(sha256=<hex>)。使用完整 whsec_… 作为密钥,对时间戳原字符串、一个英文句点和原始请求体字节计算 HMAC-SHA256。不能先解析 JSON 再序列化验签。
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWebhook(rawBody, headers, secrets) {
const timestamp = headers['x-webhook-timestamp'];
const signature = headers['x-webhook-signature'];
if (typeof timestamp !== 'string' || !/^\d+$/.test(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
if (typeof signature !== 'string' || !/^sha256=[a-f0-9]{64}$/.test(signature)) return false;
const received = Buffer.from(signature.slice(7), 'hex');
return secrets.some(secret => {
const expected = createHmac('sha256', secret).update(timestamp + '.').update(rawBody).digest();
return timingSafeEqual(expected, received);
});
}验签后检查请求体 id 与 X-Webhook-ID 相同,把事件 ID 与处理任务原子保存,尽快返回 2xx,耗时业务由自己的队列处理。通知可能重复、乱序,应按接收端点和事件 ID 去重。五分钟时间窗口限制过旧请求,事件 ID 去重阻止窗口内重复处理。
重试、记录与恢复
每轮最多尝试 3 次,间隔为 1 秒、4 秒;单次 HTTP 超时 10 秒,每次重算时间戳和签名。网络失败、429、5xx 可重试;其他 4xx、重定向、非法网络地址停止本轮投递。暂时失败可能触发后续事件重试,继续使用同一投递 ID。连续 10 轮失败会自动暂停端点。
通过测试接口和投递记录查看 outcome、http_status、累计 attempts 和 delivered_at。测试接口返回 200 只表示尝试已记录,必须检查 outcome == "delivered" 才算接收成功。修复接收服务、恢复端点,再发送测试。历史记录只保存投递元数据,不保存完整载荷,暂不提供手工重放历史事件;接收服务暂停或不可用期间,应保留任务 ID 并用任务查询补偿核对。
MCP 配置
Webhook 工具位于 full 模式。管理令牌与模型 Key 分开配置;仅使用目录和 Webhook 管理时不需要模型 Key。
{
"mcpServers": {
"tokenlab": {
"command": "npx",
"args": ["-y", "@tokenlabai/mcp-server@latest"],
"env": {
"TOKENLAB_MCP_TOOL_PROFILE": "full",
"TOKENLAB_MANAGEMENT_TOKEN": "mt-your-management-token",
"TOKENLAB_API_KEY": "sk-your-inference-key"
}
}
}
}工具包括 list_webhooks、create_webhook、get_webhook、update_webhook、delete_webhook、rotate_webhook_secret、test_webhook、list_webhook_deliveries。凭据不作为工具参数填写,只向可信 MCP 客户端授予管理访问权。
轮询兜底
Webhook 不取消查询能力,也不新增轮询限额。轮询时使用创建响应里的 poll_url,处理中逐步增加间隔,终态后停止。遇到 401、403、404 或 error.retryable == false 停止;503 async_task_owner_unavailable 属于临时故障,可退避重试。不存在或过期的任务返回 404 async_task_not_found,重复查询不能恢复或创建任务。
Seedance 兼容 API 的 callback_url 是独立的单任务回调,在创建请求中配置;它不使用这里的工作区事件载荷或 HMAC 请求头。