プラットフォーム
コールバック(Webhook)
ポーリングの代わりに、画像または動画のリクエストにcallback_urlを指定します。完了時または失敗時に、Zurelay がその URL に署名付きの結果を POST するため、送信元を確認できます。
コールバックを指定する
これらのリクエストにcallback_urlを追加します。公開インターネットからアクセスできる https URL を指定してください。
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 Acceptedx-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"}/v1/images/{id}ポーリングもできます。GET /v1/images/{id}は同じオブジェクトを返し、statusがcompletedになると、dataに新しいリンクが含まれます。response_formatの指定にかかわらず、コールバックには常にリンクが含まれ、base64 は含まれません。
送信内容
イベントごとに JSON ボディを含む POST を 1 回送ります。ボディにはtype、timestamp、そして API が返すジョブそのものを示すdata(動画オブジェクトまたは上記の画像リクエスト)が含まれます。ダウンロードリンクは 24 hours 有効です。
POST /hooks/zurelay HTTP/1.1content-type: application/jsonuser-agent: Zurelay-Webhooks/1.0 (+https://zurelay.com/docs/webhooks)webhook-id: msg_2c1f9e0b7a4d4f6e8b3a91c05d7e6f42webhook-timestamp: 1791000094webhook-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" }}署名を検証する
コールバックは、OpenAI の Webhook と同じStandard Webhooks形式に準拠しています。署名は、ワークスペースの署名用シークレットをキーに<webhook-id>.<webhook-timestamp>.<body>から生成した HMAC-SHA256 を base64 でエンコードしたものです。シークレット(whsec_で始まります)はダッシュボードのAPI キーページで確認できます。サーバー上だけで保管してください。
import osfrom fastapi import FastAPI, HTTPException, Requestfrom standardwebhooks.webhooks import Webhook # pip install standardwebhookswebhook = 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分以内にメールで回答します。