プラットフォーム

コールバック(Webhook)

ポーリングの代わりに、画像または動画のリクエストにcallback_urlを指定します。完了時または失敗時に、Zurelay がその URL に署名付きの結果を POST するため、送信元を確認できます。

コールバックを指定する

これらのリクエストにcallback_urlを追加します。公開インターネットからアクセスできる https URL を指定してください。

エンドポイント実施内容
POST /v1/videos通常どおり動画生成を開始します。終了すると、完成した動画(または失敗理由)がコールバックで届きます。ポーリングは不要です。
POST /v1/images/generations画像の完成を待たずに 202 とリクエストの id をすぐに返します。画像はバックグラウンドで生成し、完了後にコールバックします。
POST /v1/images/edits画像編集でも同じです。JSON フィールド、または multipart リクエストのフォームフィールドで指定します。
curl https://api.zurelay.com/v1/videos \
-H "Authorization: Bearer $ZURELAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedance-2.0",
"prompt": "A fox running through fresh snow at dawn",
"seconds": 5,
"callback_url": "https://example.com/hooks/zurelay"
}'

コールバック付きの画像リクエスト

callback_urlを指定しない画像リクエストは、OpenAI の API と同様に、画像の生成を待ってから結果を返します。指定した場合はすぐに受け付け、ジョブを返します。課金されるのは画像が生成された場合だけです:

レスポンス
HTTP/1.1 202 Accepted
x-request-id: req_6fJd0kQ3pW9xT2mB7cZ1hR4u
{
"id": "req_6fJd0kQ3pW9xT2mB7cZ1hR4u",
"object": "image.generation",
"model": "nano-banana-pro",
"status": "in_progress",
"created_at": 1791000000,
"completed_at": null,
"data": [],
"url_expires_at": null,
"cost": null,
"error": null,
"callback_url": "https://example.com/hooks/zurelay"
}
GET/v1/images/{id}

ポーリングもできます。GET /v1/images/{id}は同じオブジェクトを返し、statusがcompletedになると、dataに新しいリンクが含まれます。response_formatの指定にかかわらず、コールバックには常にリンクが含まれ、base64 は含まれません。

送信内容

イベントごとに JSON ボディを含む POST を 1 回送ります。ボディにはtype、timestamp、そして API が返すジョブそのものを示すdata(動画オブジェクトまたは上記の画像リクエスト)が含まれます。ダウンロードリンクは 24 hours 有効です。

イベント発生条件
video.completed動画の準備ができました。data.url からダウンロードできます。
video.failed動画を生成できませんでした。理由は data.error に記載されます。料金はかかりません。
image.completed画像の準備ができました。data.data に各画像へのリンクが含まれます。
image.failed画像を生成できませんでした。理由は data.error に記載されます。料金はかかりません。
動画のコールバック
POST /hooks/zurelay HTTP/1.1
content-type: application/json
user-agent: Zurelay-Webhooks/1.0 (+https://zurelay.com/docs/webhooks)
webhook-id: msg_2c1f9e0b7a4d4f6e8b3a91c05d7e6f42
webhook-timestamp: 1791000094
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{
"type": "video.completed",
"timestamp": "2026-10-03T03:21:34.000Z",
"data": {
"id": "video_Qm3v8Rk2Lx7Pa1Zt9Ws4Yn6B",
"object": "video",
"model": "seedance-2.0",
"status": "completed",
"progress": 100,
"created_at": 1791000000,
"completed_at": 1791000093,
"expires_at": 1793592000,
"seconds": 5,
"resolution": "720p",
"aspect_ratio": "16:9",
"size": "1280x720",
"generate_audio": true,
"url": "https://…/video_Qm3v8Rk2Lx7Pa1Zt9Ws4Yn6B.mp4?token=…",
"url_expires_at": 1791086494,
"cost": 0.45,
"error": null,
"callback_url": "https://example.com/hooks/zurelay"
}
}
画像のコールバック(ボディ)
{
"type": "image.completed",
"timestamp": "2026-10-03T03:20:41.000Z",
"data": {
"id": "req_6fJd0kQ3pW9xT2mB7cZ1hR4u",
"object": "image.generation",
"model": "nano-banana-pro",
"status": "completed",
"created_at": 1791000000,
"completed_at": 1791000041,
"data": [{ "url": "https://…/req_6fJd0kQ3pW9xT2mB7cZ1hR4u-1.png?token=…" }],
"url_expires_at": 1791086441,
"cost": 0.07,
"error": null,
"callback_url": "https://example.com/hooks/zurelay"
}
}
ヘッダー値
webhook-idmsg_…: このコールバックの再試行では毎回同じ値です。処理済みのイベントをスキップするために使います。
webhook-timestampこの送信を行った時刻です。Unix 秒で示します。
webhook-signaturev1 に続いて署名が入ります(以下を参照)。シークレットのローテーション後 1 日間は、2 つの署名がスペース区切りで入ります。
user-agentZurelay-Webhooks/1.0

署名を検証する

コールバックは、OpenAI の Webhook と同じStandard Webhooks形式に準拠しています。署名は、ワークスペースの署名用シークレットをキーに<webhook-id>.<webhook-timestamp>.<body>から生成した HMAC-SHA256 を base64 でエンコードしたものです。シークレット(whsec_で始まります)はダッシュボードのAPI キーページで確認できます。サーバー上だけで保管してください。

import os
from fastapi import FastAPI, HTTPException, Request
from standardwebhooks.webhooks import Webhook # pip install standardwebhooks
webhook = Webhook(os.environ["ZURELAY_WEBHOOK_SECRET"]) # whsec_…
app = FastAPI()
@app.post("/hooks/zurelay")
async def zurelay_hook(request: Request):
body = await request.body() # the raw bytes: the signature covers exactly these
try:
event = webhook.verify(body, dict(request.headers))
except Exception:
raise HTTPException(status_code=400)
handle(event) # event["type"], event["data"]; keep it quick, or queue it
return {"ok": True}
  • 受信したボディをそのまま検証してください。JSON をパースして再シリアライズするとバイト列が変わり、署名も一致しなくなります。
  • 5 分以上前のwebhook-timestampは拒否してください。傍受されたコールバックの再送を防げます。ライブラリを使う場合は自動で処理されます。
  • シークレットをローテーションすると(オーナーと管理者が API キーページで操作できます)、新しいシークレットがすぐに発行されます。古いシークレットも 24 hours は併用されるため、その間にサーバーを切り替えてください。

まず応答し、その後に処理する

15 seconds以内に任意の2xxを返すと、コールバックは配信済みとみなされます。まずイベントを保存して応答し、動画や画像のダウンロードはその後に行ってください。応答が途中で失われた場合など、同じコールバックが複数回届くことがあります。webhook-idを使い、各イベントを一度だけ処理してください。

再試行

それ以外の場合(エラーステータス、リダイレクト、15 seconds以内に応答がない、サーバーに接続できないなど)は再試行します。試行回数は合計 6 回です:

試行回数送信タイミング
1ジョブの終了直後
2その 1 minute 後
3さらに 5 minutes 後
4さらに 30 minutes 後
5さらに 2 hours 後
6その8時間後に再試行し、それでも失敗した場合は失敗として記録されます

各コールバックは、ダッシュボードのリクエストで元のリクエストとともに確認できます。送信先、試行ごとの応答、次の再試行時刻が表示されます。コールバックを再試行を押すと、配信済みかどうかに関係なく、すぐに再送します。コールバック内のリンクは試行ごとに新しく生成されます。

コールバックの送信先は、公開インターネット上のhttps URLに限られます。localhost、プライベートアドレス、またはそれらに解決されるURLは使えません。リダイレクトはたどらないため、最終的なURLを指定してください。開発中のテストには、トンネル(ngrok、Cloudflare Tunnel)またはリクエストインスペクターを使用してください。

ご質問や不足している情報はありますか? サポートチームにお問い合わせください。通常1分以内にメールで回答します。