最終更新
Webhook
アラートルールは、アプリ内、メール、Telegram に加えて HTTPS エンドポイントにも配信できます。すべての配信はチャネルのシークレットで署名された JSON の POST です。シークレットはチャネル作成時に一度だけ表示されます。
エンドポイントの設定
- ダッシュボードで アラート → ルール → 新しいルール を開き、イベントの種類を選んで、HTTPS の URL を指定した Webhook チャネルを追加します。API キーを使う場合は、同じルールを
POST /v1/alerts/rules(スコープwebhook:manage)に送信します。 - 署名シークレット(
whsec_…)をコピーします。シークレットはwebhookSecrets[].signingSecretで、Webhook チャネルごとに 1 つ、一度だけ返されます。エンドポイントと一緒に保管してください。 - 10 秒以内に
2xxで応答し、処理は非同期で行ってください。リダイレクトには追従せず、プライベートアドレス、ループバックアドレス、リンクローカルアドレスは拒否されます。 POST /v1/alerts/rules/{id}/testはサンプルのenvelope配信(sourceEventIdがtest_で始まるもの)を送信するので、ハンドラーの動作を確認できます。
イベント
ルールは、反応するイベントの種類を eventTypes に列挙します。空の一覧はすべての種類に一致します。アラートの対象として有用なのは次の種類です。
| 種類 | 発動条件 |
|---|---|
envelope | 監視中のルームで宝箱が観測されました。ルールのダイヤモンドの最小値が適用されます。 |
goodyBag | 監視中のルームでグッディバッグが観測されました。ルールのダイヤモンドの最小値が適用されます。 |
gift | 監視中のルームでギフトが贈られました。すべてのギフトで発動し、ダイヤモンドの最小値は適用されません。 |
minDiamondCount のデフォルトは 49 で、視聴者 1 人あたり 1.51 ダイヤモンドの下限とあわせて、宝箱とグッディバッグだけを絞り込みます。LIVE の開始・終了イベントはまだ配信されません。
ヘッダー
| ヘッダー | 値 |
|---|---|
content-type | application/json |
x-roomscope-alert-id | <ruleId>:<eventId>。ボディの alertId と同じ値です。重複排除にはこの値を使ってください。 |
x-roomscope-timestamp | この試行に署名した時刻の Unix 時間(秒)。 |
x-roomscope-schema-version | ペイロードのスキーマバージョン。現在は 2026-11-03(`links` を追加)。 |
x-roomscope-signature | sha256=<"<timestamp>.<raw body>" の HMAC-SHA256 の 16 進数>。 |
ペイロード
1 リクエストにつき 1 イベントを、コンパクトな JSON で送信します。diamondCount、peopleCount、unpackAt(Unix 秒)は envelope と goodyBag で設定され、それ以外の種類では null になります。
{ "schemaVersion": "2026-11-03", "alertId": "8f0c…:evt_…", "rule": { "id": "8f0c…", "name": "Big treasure boxes" }, "event": { "type": "envelope", "sourceEventId": "evt_…", "roomId": "7432…", "creatorUniqueId": "room.one", "region": "VN", "diamondCount": 5000, "peopleCount": 120, "score": 5000, "unpackAt": 1793520000, "observedAt": "2026-11-01T10:02:31.123Z" }, "links": { "creator": "https://app.toktokdata.live/creators/room.one", "session": "https://app.toktokdata.live/live?creator=room.one" }, "occurredAt": "2026-11-01T10:02:31.123Z", "deliveredAt": "2026-11-01T10:02:33.456Z"}署名の検証
署名は、完全な whsec_… シークレットを鍵とし、タイムスタンプヘッダー、ドット、生のボディをつなげたもの(<timestamp>.<body>)に対する HMAC-SHA256 です。16 進数のダイジェストが x-roomscope-signature に sha256=<hex> の形式で送信されます。比較は定数時間で行い、リプレイを防ぐため、任意に決めた許容範囲(以下の例では 5 分)を外れたタイムスタンプは拒否してください。
import { createHmac, timingSafeEqual } from "node:crypto"; // rawBody: the exact bytes received, e.g. express.raw({ type: "application/json" }).// secret: the full whsec_… value shown when the webhook channel was created.export function verify(rawBody, headers, secret, toleranceSec = 300) { const signature = headers["x-roomscope-signature"]; const timestamp = headers["x-roomscope-timestamp"]; if (!signature || !/^\d+$/.test(timestamp ?? "")) return false; if (Math.abs(Date.now() / 1000 - Number(timestamp)) > toleranceSec) return false; const expected = "sha256=" + createHmac("sha256", secret).update(`${timestamp}.`).update(rawBody).digest("hex"); const a = Buffer.from(signature, "utf8"); const b = Buffer.from(expected, "utf8"); return a.length === b.length && timingSafeEqual(a, b);}リトライと失敗
- 300 未満のステータスは成功です。
5xx、408、429、ネットワークエラー、タイムアウトはリトライされます。それ以外の4xxと3xxは恒久的な失敗です。 - 1 件の配信の試行は最大 4 回で、間隔を空けずに連続して送信されます。試行ごとに署名し直すため、
deliveredAt、タイムスタンプ、署名は毎回変わります。重複排除はボディではなくalertIdで行ってください。 - 配信に成功した
alertIdは、その後 7 日間は再配信されません。 - 配信された Webhook 1 件につき 1 クレジットかかります。ワークスペースが受け取れる Webhook は暦月(UTC)あたり最大 100,000 件で、それを超える配信は破棄されます。
- 失敗した配信はまだダッシュボードに表示されません。監査証跡が必要な場合は、受信したリクエストをログに記録してください。
Telegram とメール
同じルールから、接続済みの Telegram チャットやメールアドレスにも配信できます。これらのチャネルでは署名の処理は不要です。Telegram は アラート → チャネル から接続します。