RoomScope

Cập nhật lần cuối

Webhooks

An alert rule can deliver to an HTTPS endpoint next to in-app, email and Telegram. Every delivery is a JSON POST signed with the channel’s secret, which is shown once when the channel is created.

Tài liệu kỹ thuật hiện chỉ có bằng tiếng Anh.

Setting up an endpoint

  1. In the dashboard open Alerts → Rules → New rule, pick the event types and add a Webhook channel with your HTTPS URL. With an API key, send the same rule to POST /v1/alerts/rules (scope webhook:manage).
  2. Copy the signing secret (whsec_…). It is returned once, in webhookSecrets[].signingSecret, one per webhook channel. Store it with your endpoint.
  3. Answer with a 2xx within 10 seconds and do the work asynchronously. Redirects are not followed, and private, loopback or link-local addresses are refused.
  4. POST /v1/alerts/rules/{id}/test sends a sample envelope delivery (sourceEventId starts with test_) so you can check your handler.

Events

A rule lists the event types it reacts to in eventTypes; an empty list matches every type. These are the types worth alerting on:

TypeFires when
envelopeA treasure box was observed in a watched room. The rule’s minimum diamond value applies.
goodyBagA goody bag was observed in a watched room. The rule’s minimum diamond value applies.
giftA gift was sent in a watched room. Fires on every gift: the minimum diamond value does not apply.

minDiamondCount defaults to 49 and, together with a floor of 1.51 diamonds per viewer, filters treasure boxes and goody bags only. LIVE start and end events are not delivered yet.

Headers

HeaderValue
content-typeapplication/json
x-roomscope-alert-id<ruleId>:<eventId>, the same value as alertId in the body. Deduplicate on it.
x-roomscope-timestampUnix time in seconds when this attempt was signed.
x-roomscope-schema-versionPayload schema version, currently 2026-11-03 (adds `links`).
x-roomscope-signaturesha256=<hex HMAC-SHA256 of "<timestamp>.<raw body>">.

Payload

One event per request, as compact JSON. diamondCount, peopleCount and unpackAt (Unix seconds) are set for envelope and goodyBag and are null for other types.

POST your-endpoint
{  "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.roomscope.io/creators/room.one",    "session": "https://app.roomscope.io/live?creator=room.one"  },  "occurredAt": "2026-11-01T10:02:31.123Z",  "deliveredAt": "2026-11-01T10:02:33.456Z"}

Verifying signatures

The signature is HMAC-SHA256, keyed with the full whsec_… secret, over the timestamp header, a dot and the raw body: <timestamp>.<body>. The hex digest is sent as sha256=<hex> in x-roomscope-signature. Compare in constant time, and reject timestamps outside a window you choose (five minutes below) to stop replays.

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);}
Use the raw body
Parse the JSON only after the signature checks out, and compute the HMAC over the exact bytes you received. Re-serialising the object changes whitespace and escaping and breaks the comparison.

Retries and failures

  • A status below 300 is a success. A 5xx, 408, 429, network error or timeout is retried; any other 4xx or a 3xx is a permanent failure.
  • A delivery gets at most 4 attempts, sent one after another without a delay. Each attempt is signed again, so deliveredAt, the timestamp and the signature change. Deduplicate on alertId, not on the body.
  • After a successful delivery the same alertId is not delivered again for 7 days.
  • Each delivered webhook costs 1 credit. A workspace can receive up to 100,000 webhooks per calendar month (UTC); deliveries above that are dropped.
  • Failed deliveries are not listed in the dashboard yet. Log the requests you receive if you need an audit trail.

Telegram and email

The same rule can also deliver to a connected Telegram chat or to an email address; those channels need no signature handling. Connect Telegram from Alerts → Channels.

Trang này có hữu ích không?