コアガイド
Webhook管理API
Dashboard、API、またはMCPを通じたタスク通知の設定、署名の検証、および配信のトラブルシューティングを行います。
Webhookは、非同期タスクが完了、失敗、またはタイムアウトした際にアプリケーションへ通知します。Dashboard → API → Webhooks、Management API、またはTokenLab MCPのfullプロファイルを通じて設定できます。これらはワークスペースのエンドポイントと配信履歴を共有します。
使用する認証情報
| 認証情報 | 用途 | 使用場所 |
|---|---|---|
Management Token mt-… | Webhookの作成、一覧取得、更新、削除、テスト、ローテーション | /v1/management/webhooks* に対する Authorization: Bearer mt-… |
API key sk-… | モデルリクエストの送信およびタスクステータスの照会 | モデルAPIおよび /v1/tasks/{id} |
Signing secret whsec_… | 受信した通知が本物であることの検証 | 受信側(API Bearerトークンとしては絶対に使用しないでください) |
Dashboard → API → Management Tokens でManagement Tokenを作成します。トークンはワークスペース単位でスコープされます。タスクを送信するAPIキーと同じワークスペースを選択してください。トークンは他のワークスペースのエンドポイントを読み取ったり変更したりすることはできません。APIキーとSigning secretはManagement APIでは拒否されます。Dashboardの設定には、サインイン中のワークスペース管理者セッションが使用されます。
mt-… と whsec_… はバックエンドに保存してください。ブラウザコード、プロンプト、リポジトリファイル、または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":"Production task results"}'201 レスポンスには、id と whsec_ で始まる一度限りの secret が含まれます。このステップを完了する前にシークレットを保存してください。一覧取得/取得/更新のレスポンスでは表示されません。ワークスペースごとに最大10個のエンドポイントを設定できます。URLは公開HTTPSを使用する必要があり、認証情報、クエリ文字列、フラグメントを含めることはできません。リダイレクトは追跡されません。
| 操作 | エンドポイント |
|---|---|
| 一覧取得 / 作成 | GET / POST /v1/management/webhooks |
| 取得 / 更新 / 削除 | GET / PATCH / DELETE /v1/management/webhooks/{webhookId} |
| Signing secretのローテーション | 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を使用し、管理レスポンスのフィールドは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://api.tokenlab.sh/v1/media-results/7c9e6679-7425-40de-944b-e07fc1f90ae7.mp4?token=…"],
"settledCost": 0.12
}
}| イベント | データ |
|---|---|
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 | テストメッセージと設定されたサブスクリプション(テスト操作によってのみ送信) |
resultUrls の各エントリはTokenLabのメディア結果URLで、30日間有効です。データ保持を参照してください。
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 であり、ステータス読み取りで返される値と同じです。
処理前の検証
各POSTには 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による重複排除を行ってください。配信は繰り返される可能性があり、順序は保証されません。5分間のタイムスタンプ許容範囲がリプレイの有効期限を制限し、IDの重複排除がその期間内の重複処理を防ぎます。
リトライとリカバリ
各配信サイクルでは最大3回まで試行し、1秒後、次に4秒後に待機します。各HTTP試行には10秒のタイムアウトと新しいタイムスタンプ/署名が適用されます。ネットワークエラー、429、および 5xx はリトライ可能です。その他の 4xx、リダイレクト、無効なネットワークターゲットはリトライせずにそのサイクルを停止します。一時的な障害により、同じ配信IDで後のイベントリトライがトリガーされる場合があります。10回連続で失敗したサイクルは、自動的にエンドポイントを一時停止します。
テスト操作と配信履歴を使用して、outcome、http_status、attempts、delivered_at を確認してください。テストAPIの成功レスポンス (200) は試行が記録されたことを意味するのみです。outcome == "delivered" であることを確認してください。受信側を修正し、エンドポイントを再開してから、再度テストを送信してください。履歴には配信メタデータが含まれますが、ペイロードは含まれません。古いイベントの手動リプレイは利用できません。受信側が一時停止または利用不可だった場合は、タスクIDを保持し、タスクステータスと照合してください。
MCP設定
Webhook管理ツールは full プロファイルで利用可能です。管理用認証情報は推論キーとは別です。カタログおよびWebhook管理は推論キーなしでも動作します。
{
"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ヘッダーを使用しません。