APIMaster.ai

APIMaster 非同步任務 Webhooks

接收 Seedance、影片和非同步圖片任務的簽署完成與失敗通知,包含重試機制、遞送歷程和輪詢備援方案。

APIMaster 非同步任務 Webhooks

將 webhooks 作為非同步生成的主要通知機制,並保留輪詢作為備援方案。當追蹤的任務完成或失敗時,APIMaster 會發送一個經過簽署的 HTTPS POST 請求。通知與生成供應商無關,並使用您的 APIMaster 任務 ID。

支援的模型與端點

Seedance 包含全部四種模型: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 必須是一個可公開存取的 HTTPS 端點,使用埠 443。私有地址和重新導向會被拒絕。每個帳戶最多允許 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 秒內回傳 HTTP 200 並附上 {"challenge":"THE_RECEIVED_CHALLENGE"}。引用未驗證、已暫停或屬於其他帳戶的端點的生成請求,將在提交前被拒絕。

HTTP 請求總逾時為 10 秒(包括 DNS、連線和 TLS 握手),送出請求後等待回應標頭的上限為 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 替換為四個 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,以在所有子任務完成後接收一批次摘要。其狀態為 completed、partial_failure 或 failed,計數位於 data.summary 中。批次完成並不總是意味著每個子任務都成功。

請使用屬於任務帳戶的 API 金鑰下載輸出 URL。請及時保存生成的媒體。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 驗證。使用恆定時間比較,允許最多五分鐘的時鐘偏差,並檢查 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 日最多允許五次手動重播。當前已租用進行傳遞的事件,在該次嘗試結束或其租約到期之前無法重播。

使用 PATCH /v1/webhook-endpoints/{id} 和 {"enabled":false} 或 {"enabled":true} 來暫停或恢復端點。恢復會繼續處理那些原始截止時間尚未過去的已暫停事件。使用 POST /v1/webhook-endpoints/{id}/rotate-secret 輪換密鑰;保存新的密鑰和 kid,並在返回的 24 小時過渡期內保留先前的一對密鑰。

輪詢備用方案

對於未收到終端事件的任務,請每 60 至 120 秒查詢一次 /v1/videos/{task_id} 或模型文件中記載的圖像任務查詢。使用任務 API 作為真實來源,並在生成已完成但通知遺失時檢查傳遞歷史記錄。Webhook 遺失不是重新提交可計費生成請求的理由。端點持續停機可能耗盡自動重試次數;請恢復接收器並重播保留的事件。