開発者向け
時間のかかる処理に、頼れる合図を
ジョブ、ドメイン、公開、承認の変更時に、署名付きHTTPSリクエストを少なくとも一度届けます。
エンドポイントを登録する
開発者ページでエンドポイントを追加するか、webhooks:writeスコープで追加します。
curl -s -X POST "$BASE/workspaces/$WS/webhooks" \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: $(openssl rand -hex 16)" \
-H "Content-Type: application/json" \
-d '{"url":"https://hooks.example.com/mini-casa","events":["job.updated","publication.updated"]}'レスポンスには、一度だけ表示されるsigning_secret(whsec_...)が含まれます。URLは443番ポートのHTTPSで、公開アドレスだけに名前解決される必要があります。プライベート、ループバック、内部の宛先は拒否し、配信のたびに再検証し、リダイレクトには決して従いません。一つのワークスペースで、稼働中のエンドポイントを最大10個持てます。
管理していることを証明する
新しいエンドポイントはpending_verificationで始まります。検証ボタン(またはPOST /webhooks/{id}/verify)は、署名付きのwebhook.challengeを一度送ります。2xxと{"challenge": "<data.challenge>"}を返すと、エンドポイントはactiveになります。
イベント
job.updated:ジョブや一括実行の状態が変わります。job.item.updated:一括実行の一項目の状態が変わります。domain.updated:独自ドメインのチェックが進みます。publication.updated:ビルドが開始、成功、失敗、または新しいビルドに置き換わります。approval.updated:承認が決定、期限切れ、または使用済みになります。billing.entitlement.updated:プランや利用権が変わります。
本文にはIDと状態だけを含み、認証情報、コンテンツ、個人データは決して含みません。現在の状態はAPIで取得してください。
すべてのリクエストを検証する
各リクエストにはSmallWorld-Webhook-Id、SmallWorld-Webhook-Timestamp(Unix秒)、SmallWorld-Webhook-Signature(v1=<hex>,kid=<key id>)があります。署名は、シークレットを使った<timestamp>.<raw body>のHMAC-SHA256です。JSON解析前の生の本文を使い、定時間で比較し、自分の時計から五分を超えて離れたタイムスタンプは拒否してください。
import crypto from "node:crypto";
export function verify(secret, timestamp, rawBody, header) {
const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
const given = /v1=([a-f0-9]+)/.exec(header)?.[1] ?? "";
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
return fresh && given.length === expected.length
&& crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
}配信の保証
- 少なくとも一度。
2xxを返すまでリクエストを繰り返します。イベントIDはすべての再試行と再配信で同じなので、保存し、すでに見たIDは無視してください。 - 再試行の間隔は一分から一日へと延び、合計72時間続きます。その後は未配信の扱いとなり、開発者ページか
redeliver_webhookから再送できます。 - 10イベント続けて未配信になったエンドポイントは、再開するまで一時停止します。
- 順序は保証しません。状態は手掛かりとして扱い、リソースを読み取ってください。