API Webhooks ガイド
署名付き Rivya API webhook endpoint を作成し、delivery 署名を検証し、delivery 試行を確認し、安全なテストイベントを送信します。
2026/05/11 最終レビュー
Public API の生成が終端状態に到達した後、Rivya からサーバーへ通知させたい統合では API webhooks を使います。
GET /api/v1/generations/{taskId} によるポーリングは引き続きサポートされます。Webhooks は、イベント delivery を好む本番システム向けに署名付き callback を追加します。
必要なスコープ
Webhook 管理には、次のスコープを持つ API キーが必要です。
webhooks:manageSettings で新しく作成したキーには、このスコープがデフォルトで含まれます。
Endpoint を作成する
POST /api/v1/webhookscurl https://rivya.ai/api/v1/webhooks \
-H "Authorization: Bearer rvya_sk_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Production webhook",
"url": "https://example.com/rivya/webhook",
"event_types": ["generation.succeeded", "generation.failed"]
}'応答には signing_secret が一度だけ含まれます。
{
"id": "whend_...",
"object": "webhook_endpoint",
"name": "Production webhook",
"url": "https://example.com/rivya/webhook",
"event_types": ["generation.succeeded", "generation.failed"],
"status": "active",
"secret_preview": "whsec_12...abc123",
"signing_secret": "whsec_...",
"last_success_at": null,
"last_failure_at": null,
"failure_count": 0,
"created_at": "2026-05-11T00:00:00.000Z",
"updated_at": "2026-05-11T00:00:00.000Z",
"disabled_at": null,
"revoked_at": null
}完全な secret はサーバーに保存してください。失った場合は rotate endpoint を呼び出し、受信側を更新してください。
URL ルール
Endpoint URL は HTTPS である必要があります。Rivya は credentials、fragments、localhost 名、ローカルネットワークアドレス、プライベート IP 範囲、loopback アドレス、予約済みアドレスを含む URL を拒否します。
Rivya は常に次を送信します。
POSTContent-Type: application/json- ユーザー制御のカスタムリクエストヘッダーなし
- 自動リダイレクト追従なし
- 短い delivery timeout
イベント
現在のイベントタイプ:
generation.succeededgeneration.failed
Webhook payload は、ステータスエンドポイントと同じ公開 generation serializer を使います。
{
"id": "evt_...",
"type": "generation.succeeded",
"api_version": "2026-05-11",
"created_at": "2026-05-11T00:00:00.000Z",
"data": {
"generation": {
"id": "task_public_id",
"status": "succeeded",
"model": "z-image",
"reserved_credits": 1,
"final_credits": 1,
"created_at": "2026-05-11T00:00:00.000Z",
"updated_at": "2026-05-11T00:01:00.000Z",
"result": {
"primary_url": "https://...",
"urls": ["https://..."]
},
"error": null
}
}
}Delivery ヘッダー
各 delivery には次が含まれます。
Rivya-Webhook-Id: evt_...
Rivya-Webhook-Timestamp: 1778467200
Rivya-Webhook-Signature: v1=<hex-hmac-sha256>
Rivya-Webhook-Attempt: 1
Rivya-Webhook-Endpoint-Id: whend_...
Rivya-Request-Id: req_...署名入力:
${timestamp}.${rawBody}アルゴリズム:
HMAC-SHA256 with the endpoint signing secret古いタイムスタンプのリクエストは拒否してください。5 分の許容幅が実用的なデフォルトです。
JavaScript 検証
import crypto from "node:crypto";
function verifyRivyaWebhook({ rawBody, headers, signingSecret }) {
const timestamp = headers["rivya-webhook-timestamp"];
const signature = headers["rivya-webhook-signature"] || "";
const actual = signature.split(",").find((part) => part.startsWith("v1="))?.slice(3);
const expected = crypto
.createHmac("sha256", signingSecret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
if (!actual) return false;
return crypto.timingSafeEqual(Buffer.from(actual, "hex"), Buffer.from(expected, "hex"));
}Python 検証
import hmac
import hashlib
def verify_rivya_webhook(raw_body: str, headers: dict, signing_secret: str) -> bool:
timestamp = headers.get("rivya-webhook-timestamp", "")
signature = headers.get("rivya-webhook-signature", "")
actual = next((part[3:] for part in signature.split(",") if part.startswith("v1=")), "")
expected = hmac.new(
signing_secret.encode(),
f"{timestamp}.{raw_body}".encode(),
hashlib.sha256,
).hexdigest()
return bool(actual) and hmac.compare_digest(actual, expected)Endpoints を管理する
GET /api/v1/webhooks
GET /api/v1/webhooks/{endpointId}
PATCH /api/v1/webhooks/{endpointId}
DELETE /api/v1/webhooks/{endpointId}
POST /api/v1/webhooks/{endpointId}/rotate-secretcurl https://rivya.ai/api/v1/webhooks \
-H "Authorization: Bearer rvya_sk_..."
curl https://rivya.ai/api/v1/webhooks/whend_... \
-H "Authorization: Bearer rvya_sk_..."
curl -X PATCH https://rivya.ai/api/v1/webhooks/whend_... \
-H "Authorization: Bearer rvya_sk_..." \
-H "Content-Type: application/json" \
-d '{"status":"disabled"}'
curl -X POST https://rivya.ai/api/v1/webhooks/whend_.../rotate-secret \
-H "Authorization: Bearer rvya_sk_..."DELETE /api/v1/webhooks/{endpointId} は endpoint を無効化します。delivery 履歴は削除しません。
Delivery 記録
最近のイベントを一覧します。
GET /api/v1/webhook-eventscurl https://rivya.ai/api/v1/webhook-events \
-H "Authorization: Bearer rvya_sk_..."endpoint の delivery 試行を一覧します。
GET /api/v1/webhooks/{endpointId}/deliveriescurl https://rivya.ai/api/v1/webhooks/whend_.../deliveries \
-H "Authorization: Bearer rvya_sk_..."Delivery 記録には、status、HTTP status、attempt number、request id、duration、切り詰められた response snippet、公開エラーフィールドが含まれます。
テストイベント
安全なテスト payload を送信します。
POST /api/v1/webhooks/{endpointId}/testcurl -X POST https://rivya.ai/api/v1/webhooks/whend_.../test \
-H "Authorization: Bearer rvya_sk_..."テストイベントは webhook.test を使います。生成タスクを作成せず、クレジットを消費せず、実際の結果 URL を含みません。
リトライポリシー
Rivya は HTTP 2xx を成功として扱います。
失敗には、ネットワークエラー、timeout、redirect 応答、非 2xx 応答が含まれます。Rivya は最大 5 回試行します。
- 即時
- 1 分後
- 5 分後
- 30 分後
- 2 時間後
最後の試行後も失敗した場合、イベントは failed としてマークされます。
Webhook delivery の失敗は、生成ステータス、クレジット、返還、タスク履歴を変更しません。
セキュリティチェックリスト
- ビジネスロジックを解析する前に HMAC 署名を検証します。
- 古いタイムスタンプを拒否します。
- テストイベントと生成イベントを分けて扱います。
- 完全な signing secret をログに記録しません。
- 受信側がイベントを受け入れた後にのみ
2xxを返します。 - 照合用の fallback としてポーリングを残します。