APIMaster 非同期タスク Webhook
Seedance、動画、非同期画像タスクの署名付き完了通知と失敗通知を受け取り、リトライ、配信履歴、ポーリングフォールバックを利用できます。
APIMaster 非同期タスク Webhook
非同期生成の主要な通知メカニズムとして Webhook を使用し、ポーリングはフォールバックとして維持します。APIMaster は、追跡対象のタスクが完了または失敗したときに署名付き HTTPS POST を送信します。通知は生成プロバイダーに依存せず、お客様の APIMaster タスク ID を使用します。
対応モデルとエンドポイント
Seedance は 4つのモデルすべて を含みます: seedance-2.0、seedance-2.5、seedance-2.0-fast、seedance-2.0-mini。POST /v1/videos/generations または互換性のある POST /v1/video/generations を使用してください。
動画タスク通知は、MiniMax-H3、Kling Omni / Motion Control、Grok Imagine Video、Sora もサポートしています。対応する GPT Image 2 / 2.5 および Gemini 画像ワークフローでは /v1/images/generations/async または対応する /v1/images/edits/async を使用します。Midjourney v8.2 / Niji 7 では /v1/midjourney/generations を使用します。ルートの可用性と生成パラメータは、各モデルのガイドに従います。同期型の Seedream および Grok 画像生成、チャットストリーミング、Seedance アセットレビューは、この生成 Webhook 契約の対象外です。
モデルの適格性については GET /v1/webhook-capabilities?model=seedance-2.0-fast を確認してください。対応する非同期送信エンドポイントを使用してください。適格性は、すべての画像操作またはすべてのモデルエイリアスが非同期生成をサポートすることを意味するわけではありません。
エンドポイントの登録と検証
Authorization: Bearer YOUR_API_KEY で API キーを使用してください。API キーは、そのアカウントに属するエンドポイントとイベントを管理できます。サーバー上で保管してください。
curl --fail-with-body "https://apimaster.ai/v1/webhook-endpoints" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.example/webhooks/apimaster"}'
レスポンスには endpoint.id、endpoint.key_id、signing_secret が含まれます。署名シークレットは安全に保存してください。これは一度だけ返されます。これは API キーとは別のものであり、生成やダウンロードの認可には使用できません。URL はポート 443 で公開到達可能な HTTPS エンドポイントである必要があります。プライベートアドレスやリダイレクトは拒否されます。アカウントごとに最大 20 のエンドポイントが許可されます。URL は不変なので、宛先を変更する際は新しいエンドポイントを作成して検証してください。
受信側を設定した後、所有権を検証します:
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-endpoints/whep_example/verify" \
-H "Authorization: Bearer YOUR_API_KEY"
APIMaster は data.challenge を含む署名付き webhook.endpoint_verification イベントを送信します。10 秒以内に {"challenge":"THE_RECEIVED_CHALLENGE"} を含む HTTP 200 を返してください。未検証、一時停止、または別のアカウントのエンドポイントを参照する生成リクエストは、送信前に拒否されます。
HTTPリクエスト全体のタイムアウトは、DNS、接続、TLSを含めて10秒です。送信後8秒以内にレスポンスヘッダーを返してください。イベントを永続化したら、速やかに受信を確認してください。
通知付きでタスクを送信する
curl --fail-with-body "https://apimaster.ai/v1/videos/generations" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model":"seedance-2.5",
"prompt":"A paper boat floating on a calm pond, slow camera movement.",
"duration":4,
"resolution":"480p",
"aspect_ratio":"16:9",
"notifications":{
"webhook":{
"endpoint_id":"whep_example",
"events":["task.completed","task.failed"]
}
},
"client_reference_id":"order_123"
}'
モデル ID を 4つの Seedance ID のいずれかに置き換え、そのモデル独自の対応パラメータを維持してください。通常の作成レスポンスからタスク ID を保存してください。client_reference_id は最大 128 バイトのオプションのビジネス参照用識別子です。これは送信の冪等性キーではありません。notifications を従来の webhook または callback_url プロバイダーパラメータと組み合わせないでください。
対応するマルチパート画像編集では、notifications を JSON 文字列フォームフィールドとして、client_reference_id を別のフォームフィールドとして送信します:
curl --fail-with-body "https://apimaster.ai/v1/images/edits/async" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "model=gpt-image-2" \
-F "prompt=Turn the reference into a watercolor illustration" \
-F "image=@reference.png" \
-F 'notifications={"webhook":{"endpoint_id":"whep_example","events":["task.completed","task.failed"]}}' \
-F "client_reference_id=image_order_123"
このバージョンではアカウント全体のデフォルトエンドポイントはありません。各タスクリクエストでエンドポイントを参照してください。Webhook は送信レスポンスよりも先に到着する場合があります。アプリケーションが返されたタスク ID をまだ保存していなくても、それらを永続化してください。一部の画像非同期ワークフローは同期型の上流生成をラップしているため、送信自体に時間がかかる場合があります。
成功と失敗のペイロード
成功通知には公開タスク ID と認証済み動画リンクが含まれます:
{
"id":"evt_example",
"type":"task.completed",
"api_version":"2026-10-03",
"created_at":1791014400,
"data":{
"task_id":"task_example",
"model":"seedance-2.5",
"kind":"video",
"status":"completed",
"client_reference_id":"order_123",
"completed_at":1791014400,
"task_url":"https://apimaster.ai/v1/videos/task_example",
"result":{
"outputs":[{
"output_id":"0",
"type":"video",
"url":"https://apimaster.ai/v1/videos/task_example/content",
"authentication":"bearer",
"expires_at":null
}]
},
"error":null
}
}
失敗は同じエンベロープを使用し、type: "task.failed"、data.status: "failed"、data.result: null、およびエラーオブジェクトが含まれます:
{
"code":"generation_failed",
"message":"The generation task failed. Query the task for details."
}
プロバイダー確認済みの失敗とゲートウェイタスクタイムアウトの両方が失敗イベントを生成する可能性があります。タスクが受け入れられる前に拒否された作成リクエストは、タスクイベントを生成しません。通知配信の失敗は生成ステータスを変更せず、生成を再実行しません。イベントは課金調整が完了したことを確認するものではありません。
画像の場合、kind は image であり、outputs には利用可能なすべての画像出力が含まれます。Midjourney 子タスクイベントには batch_id が含まれます。さらに batch.completed に登録して、すべての子タスク完了後に 1 回のバッチ要約を受け取ることもできます。そのステータスは completed、partial_failure、failed のいずれかで、カウントは data.summary に含まれます。バッチ完了は必ずしもすべての子タスクが成功したことを意味しません。
出力 URL は、タスクのアカウントに属する API キーでダウンロードしてください。生成されたメディアは速やかに保存してください。expires_at: null は、永続的な保存ではなく、保証された有効期限が提供されないことを意味します。後でダウンロードすると HTTP 410 が返される場合があります。イベントを再生してもメディアの可用性は延長されません。
コールバックの認証と迅速な応答確認
各POSTリクエストには以下が含まれます:
X-APIMaster-Event-ID: evt_example
X-APIMaster-Delivery-ID: dlv_example
X-APIMaster-Timestamp: 1791014400
X-APIMaster-Signature: v1=<hex-hmac>,kid=<key-id>
エンドポイントの署名シークレットを使用して、タイムスタンプ、リテラルのドット、および生のリクエストボディバイトに対してHMAC-SHA256を検証してください。定数時間比較を使用し、最大5分のクロックスキューを許容し、Event-IDヘッダーがボディのIDと一致することを確認してください。再試行では同じイベントIDとボディが保持されますが、新しい配信ID、タイムスタンプ、および署名を受け取ります。
以下のPythonレシーバーはFlaskとSQLiteを使用しています。これは、イベントを応答確認する前にアトミックに永続化します。アプリケーションワーカーは、保存された行を消費し、ファイルをダウンロードし、ビジネスロジックを別途実行する必要があります。
import hashlib, hmac, json, os, sqlite3, time
from flask import Flask, request, jsonify, abort
app = Flask(__name__)
# During key rotation, configure both active and previous kid/secret pairs.
SECRETS = json.loads(os.environ["APIMASTER_WEBHOOK_SECRETS_JSON"])
DB_PATH = os.environ.get("WEBHOOK_DB_PATH", "webhook-events.sqlite3")
with sqlite3.connect(DB_PATH) as db:
db.execute("CREATE TABLE IF NOT EXISTS events (id TEXT PRIMARY KEY, body BLOB NOT NULL)")
@app.post("/webhooks/apimaster")
def receive():
raw = request.get_data()
try:
timestamp = request.headers["X-APIMaster-Timestamp"]
if abs(time.time() - int(timestamp)) > 300:
abort(401)
fields = dict(part.split("=", 1) for part in
request.headers["X-APIMaster-Signature"].split(","))
secret = SECRETS[fields["kid"]]
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + raw,
hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, fields["v1"]):
abort(401)
event = json.loads(raw)
if event["id"] != request.headers["X-APIMaster-Event-ID"]:
abort(401)
except (KeyError, ValueError, TypeError):
abort(401)
if event["type"] == "webhook.endpoint_verification":
return jsonify(challenge=event["data"]["challenge"])
with sqlite3.connect(DB_PATH) as db:
db.execute("INSERT OR IGNORE INTO events(id, body) VALUES (?, ?)",
(event["id"], raw))
return "", 204
生成イベントに対しては、10秒以内に任意の2xxステータスを返してください。メディアのダウンロードを待たずに、耐久性のあるストレージへの保存後に応答確認を行ってください。配信は少なくとも一度です:特に応答確認が失われた場合、重複イベントが発生する可能性があるため、idによって重複排除を行ってください。タスク間の順序保証はありません。
再試行、配信履歴、およびリプレイ
APIMasterは、ネットワーク障害、応答確認タイムアウト、および非2xx応答に対して、イベント作成から最大72時間まで再試行します。初期の遅延は1、2、5、15、30分、次に1、2、4、8時間、その後は12時間間隔で、最大20%のジッターが加えられます。429/503応答での有効なRetry-Afterは、再試行ウィンドウ内で尊重されます。リダイレクトは追従されません。HTTP 410はエンドポイントを一時停止します;その他の4xx応答は、設定修正を可能にするために再試行されます。
curl --fail-with-body "https://apimaster.ai/v1/webhook-events?task_id=task_example" \
-H "Authorization: Bearer YOUR_API_KEY"
curl --fail-with-body "https://apimaster.ai/v1/webhook-events/evt_example/deliveries" \
-H "Authorization: Bearer YOUR_API_KEY"
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-events/evt_example/redeliver" \
-H "Authorization: Bearer YOUR_API_KEY"
ステータスには、pending、in_flight、retrying、delivered、paused、およびexhaustedが含まれます。イベントおよび試行記録は30日間保持されます。リプレイは元のイベントIDとペイロードを保持し、新しい72時間の配信ウィンドウを開きます;メディアの再生成や追加課金は発生しません。イベントごとにUTC日あたり最大5回の手動リプレイが許可されます。現在配信用にリースされているイベントは、その試行が終了するかリースが期限切れになるまでリプレイできません。
エンドポイントの一時停止または再開は、PATCH /v1/webhook-endpoints/{id}および{"enabled":false}または{"enabled":true}で行います。再開は、元の期限が過ぎていない一時停止されたイベントを継続します。シークレットのローテーションはPOST /v1/webhook-endpoints/{id}/rotate-secretで行います;新しいシークレットとkidを保存し、返された24時間の移行期間中は以前のペアを保持してください。
ポーリングフォールバック
受信された終端イベントがないタスクについては、/v1/videos/{task_id}またはモデルのドキュメントに記載された画像タスククエリを60〜120秒ごとにクエリしてください。タスクAPIを信頼できる情報源として使用し、生成が完了しているが通知が欠落している場合は配信履歴を確認してください。ウェブフックの欠落は、課金対象の生成リクエストを再送信する理由にはなりません。エンドポイントの持続的なダウンタイムは自動再試行を枯渇させる可能性があります;レシーバーを復旧し、保持されているイベントをリプレイしてください。
