仕組み
- タスク呼び出しごとに一意のオペレーション ID が生成されます
- そのID(および他のルーティングパラメーター)を URL テンプレートに代入して Webhook URL が構築されます
push_notification_configがその URL と HMAC 認証情報とともにタスクリクエストボディに注入されます- タスクのステータスが変化するたびに、パブリッシャーが Webhook 通知を URL に POST します
- 各通知はペイロード内に
operation_idをエコーバックするため、URL を解析せずに相関付けできます
@adcp/client ライブラリを使用している場合、このフロー全体は自動的に処理される — クライアントに webhookUrlTemplate と webhookSecret を一度設定すると、push_notification_config がすべての送信タスク呼び出しに注入されます。
命名規則: snake_case vs camelCase
混乱しやすい点があります。2つの命名規則が存在する:| コンテキスト | フィールド名 | 例 |
|---|---|---|
| MCP タスク引数(AdCP JSON) | push_notification_config | { push_notification_config: { url: ... } } |
| A2A 設定オブジェクト | pushNotificationConfig | configuration: { pushNotificationConfig: { url: ... } } |
push_notification_config(snake_case)だ。他のタスクパラメーターと並んでタスクリクエストボディに含めます。
A2A の場合、A2A プロトコルが camelCase を使用して configuration エンベロープにラップするが、オブジェクトの内容は同一です。
リクエストへの push_notification_config の追加
MCP
push_notification_config をタスク引数として、他のタスクパラメーターとマージして含める:
A2A
A2A の場合、スキルパラメーターはmessage.parts[].data.parameters に格納します。プッシュ通知設定はトップレベルの configuration オブジェクトに入れる:
オペレーション ID と URL テンプレート
オペレーション ID により、受信した Webhook を適切なハンドラーにルーティングできます。典型的なパターン:- タスク呼び出しごとに一意の ID を生成します
- Webhook URL パスに埋め込む
- パブリッシャーがペイロードで
operation_idをエコーする — URL 解析は不要
"operation_id": "cd51e063-2b79-4a6d-afac-ed7789c3a443" が含まれるため、URL を解析せずに正しい保留オペレーションにルーティングできます。
Webhook が送信される条件
Webhook は、リクエストにpush_notification_config が含まれている限り、最初のレスポンス以降の各ステータス変化に対して送信されます。
タスクが同期的に完了した場合(最初のレスポンスがすでに completed または failed)、Webhook は送信されない — すでに結果が手元にあるためです。
Webhook をトリガーするステータス変化:
| Status | 意味 |
|---|---|
working | タスクが処理中 — 進捗情報が含まれることがある |
input-required | 人の承認または確認待ち |
completed | 最終結果が利用可能 |
failed | タスクがエラー詳細とともに失敗 |
canceled | タスクがキャンセルされた |
Webhook ペイロード形式
MCP
A2A
A2A は最終状態に対してTask オブジェクト、進捗には TaskStatusUpdateEvent を送信します。AdCP の結果データは status.message.parts[].data に含まれます:
プロトコル比較
| MCP | A2A | |
|---|---|---|
| 設定フィールド | push_notification_config(タスク引数内) | configuration.pushNotificationConfig(スキルパラメーターとは別) |
| エンベロープ | mcp-webhook-payload.json | ネイティブの Task / TaskStatusUpdateEvent |
| 結果の場所 | result フィールド | status.message.parts[].data |
| データスキーマ | 同一の AdCP スキーマ | 同一の AdCP スキーマ |
ステータス別結果データ
| Status | result / data の内容 |
|---|---|
completed / failed | 完全なタスクレスポンス |
working | 進捗: percentage、current_step、total_steps |
input-required | 理由と任意のバリデーションエラー |
submitted | 最小限の受付確認 |
認証
Bearer トークン
シンプルなトークン認証 — パブリッシャーがAuthorization ヘッダーでトークンを送信します。
設定:
HMAC-SHA256(本番環境推奨)
パブリッシャーが共有シークレットで各リクエストに署名し、リプレイ保護のためのタイムスタンプを含めます。受信側は署名とタイムスタンプの両方を検証します。 設定:{unix_timestamp}.{raw_json_body} だ — Unix タイムスタンプ(秒)、ドット、HTTP ボディとして送信される JSON バイトそのもの。
rawBody はワイヤー上で送信される正確なバイトでなければなりません。実装では HTTP ボディと同じシリアライゼーションで署名しなければなりません — 再シリアライズまたは再フォーマットされたバージョンへの署名は検証失敗を引き起こす。
パブリッシャー実装(署名):
express.json() の verify コールバックを使用して生ボディをキャプチャできる:
X-ADCP-Timestamp ヘッダーに Unix タイムスタンプ(秒単位、ISO 8601 ではない)を使用しなければなりません。受信側は |current_time - timestamp| > 300 秒のリクエストを拒否すべきです。
:::
信頼性
Webhook は少なくとも1回の配信を使用する — 同じイベントが複数回受信される場合があり、イベントが順序通りに届かない場合もあります。 これに対処するためにtask_id + status + timestamp を使用します:
ベストプラクティス
- 常にポーリングをバックアップとして実装する — Webhook は失敗することがあります。Webhook が設定されている場合は間隔を減らして(例: 2 分ごと)ポーリングし、終端ステータスを受信したら停止します
- 重複を処理する —
task_id+timestampを使用して、既に処理済みまたは順序外のイベントをスキップします - 署名を検証する — 処理前に常に
X-ADCP-Signatureを検証します - すぐに応答を返す — パブリッシャーのタイムアウトや不要なリトライを避けるため、重い処理の前に
200を返す - URL 構造に依存しない — ルーティングには URL 解析ではなくペイロードの
operation_idを使用します - 本番環境では HMAC-SHA256 を使用する — Bearer トークンはシンプルだがペイロードの改ざんを防げない
レポート Webhook
レポート Webhook はタスクステータス Webhook とは別物です。アクティブなメディアバイの定期的なパフォーマンスデータを配信し、push_notification_config ではなく create_media_buy の reporting_webhook で設定します。
詳細についてはタスクリファレンスの reporting_webhook を参照。
次のステップ
- タスクライフサイクル — ステータス値と遷移
- 非同期オペレーション — 長時間タスクの処理
- エラーハンドリング — Webhook エラーパターン