アプリに組み込む
結果のコールバック
Webhook は、タスクの完了からアプリがそれを知るまでの遅延を短縮します。これは配信の最適化です:3 回試行した後、ゲートウェイは試行をやめます。信頼できる情報源は引き続きステータスエンドポイントです。
#送信時にコールバックを登録
送信リクエストに webhook_url を指定します。webhook_secret を加えるとすべての配信に署名が付きます — 加えなければ、署名は一切付きません。
curl https://www.aisplice.store/v1/videos \
-H "Authorization: Bearer sk-YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: video-job-8842" \
-d '{
"model": "doubao-seedance-2.5",
"prompt": "A cinematic product scene",
"webhook_url": "https://your.app/hooks/ai-tasks",
"webhook_secret": "whsec_replace_me"
}'パブリックにルーティング可能であること
localhost、127.0.0.1、プライベートアドレス帯、リンクローカル、クラウドのメタデータアドレスは、タスク送信時に拒否されます — 配信時ではありません。開発中はトンネルを使用してください。
http または https で、送信時に名前解決できること
ホスト名を名前解決し、返されたすべてのアドレスをチェックします。名前解決できないと送信は失敗します。
配信はベストエフォート
3 回再試行した後、ゲートウェイは配信をやめてログのみ記録します。信頼できる情報源は引き続きステータスエンドポイントです。
localhost はタスク送信時に拒否される
#ヘッダーとペイロード
| ヘッダー | 送信される条件 | 使い方 |
|---|---|---|
| X-Xiaoxiang-Signature | タスクを webhook_secret 付きで送信した場合のみ。 | sha256=<生のボディの HMAC-SHA256(16 進)>。パースする前に、定数時間比較で検証してください。 |
| X-Xiaoxiang-Event | すべての配信。 | task.completed または task.failed — ペイロードから意図を推測し直さず、この値で振り分けてください。 |
| X-Xiaoxiang-Event-Id | すべての配信。 | 同じイベントの再試行間で変わりません。保存して重複を破棄してください — これが重複排除キーです。 |
| フィールド | 型 | 含まれる条件 | 説明 |
|---|---|---|---|
| event_id | string | 常に | X-Xiaoxiang-Event-Id と一致します。これで重複排除してください。 |
| event | string | 常に | "task.completed" または "task.failed"。 |
| task_id | string | 常に | 送信時の呼び出しで返された id — 突き合わせ用のキーです。 |
| status | string | 常に | 動画の語彙による終了ステータス — 画像や音楽のタスクでも "completed" または "failed" です。 |
| model | string | 判明している場合 | タスクを生成したモデル。不明な場合は省略されます。 |
| url | string | 成功時 | タスク成功時の結果 URL。安定したプラットフォームのリンクには /content を推奨します。 |
| fail_reason | string | 失敗時 | 失敗時のみ含まれます。 |
| quota | integer | 常に | 実際に消費した利用枠(内部単位)。照合にはこのフィールドではなく使用量ログを使ってください。 |
| created_at | integer | 常に | タスク送信時刻(Unix 秒)。 |
| finished_at | integer | 常に | 終了状態に遷移した時刻(Unix 秒)。 |
{
"event_id": "task_8f21c...:task.completed",
"event": "task.completed",
"task_id": "8f21c0d2-...",
"status": "completed",
"model": "doubao-seedance-2.5",
"url": "https://cdn.example.com/renders/8f21c0d2.mp4",
"quota": 128000,
"created_at": 1789000000,
"finished_at": 1789000184
}#生のリクエストボディを検証
JSON をパースする前に、受信したバイト列そのものに対して HMAC-SHA256 を計算してください — ペイロードを再シリアライズするとバイト列が変わり、比較が失敗します。定数時間で比較し、一致しなければ拒否してください。
import crypto from "node:crypto";
// Express: express.raw({ type: "application/json" }) — not express.json().
export function handleTaskWebhook(req, res) {
const received = req.get("X-Xiaoxiang-Signature") ?? "";
const expected =
"sha256=" +
crypto.createHmac("sha256", process.env.WEBHOOK_SECRET)
.update(req.body) // Buffer of the raw body
.digest("hex");
const a = Buffer.from(received);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString("utf8"));
// Deduplicate first, acknowledge fast, then do the work off-request.
if (!seen.add(req.get("X-Xiaoxiang-Event-Id"))) return res.status(200).end();
queue.push(event);
res.status(200).end();
}#配信と重複排除
15 秒以内に応答する
これが配信のタイムアウトです。それより遅いと失敗した試行と見なされるため、処理はキューに入れて先に 2xx を返してください。
イベント ID で重複排除する
X-Xiaoxiang-Event-Id は再試行間で変わりません。業務データを変更する前に保存し、重複を破棄してください。
再試行は 3 回、その後は届かない
配信に失敗すると、5 秒後、30 秒後、2 分後に再試行します。その後、ゲートウェイはログを記録するだけです — それ以上は何も届きません。
#照合用のポーラーを維持
Webhook の配信はベストエフォート
まだ解決しませんか?
リクエスト ID かエラーメッセージを送っていただければ、こちらで調査します。