Last updated
Webhooks
An alert rule can deliver to an HTTPS endpoint next to in-app, email and Telegram. Deliveries are JSON POSTs signed with a per-rule secret that is shown once when the rule is created.
Setting up an endpoint
- In the dashboard open Alerts → Rules → New rule, pick the event types and a minimum diamond value, and add a Webhook channel with your HTTPS URL.
- Copy the signing secret from the confirmation. It is shown once; store it with your endpoint.
- Respond with any 2xx within a few seconds. Do the work asynchronously.
Events
| Type | Fires when |
|---|---|
live_start | A watched creator went live. |
gift | A gift at or above the rule’s minimum diamond value was sent in a watched room. |
envelope | A treasure-box / red-envelope event was observed in a watched room. |
goodyBag | A goody-bag event was observed in a watched room. |
Rules also support pacing so a busy room does not flood your endpoint: when a rule is paced, only the first matching event in the window is delivered.
Payload
One event per request. The data object depends on type; the example shows a gift. Field names in data are Subject to change.
{ "id": "evt_01J9X4R7Q2M8V3K6N5P1T0ZWAB", "type": "gift", "createdAt": "2026-11-01T10:02:33Z", "workspaceId": "ws_…", "ruleId": "rule_…", "data": { "roomKey": "…", "creatorUid": "7123456789012345678", "uniqueId": "room.one", "diamonds": 5000, "giftName": "…", "observedAt": "2026-11-01T10:02:31Z" }}Verifying signatures
Every delivery is signed with HMAC-SHA256 over the raw request body using the rule’s signing secret. Compute the same digest and compare it in constant time with the value in the signature header (X-RoomScope-Signature header name subject to change). Reject anything that does not match.
import { createHmac, timingSafeEqual } from "node:crypto"; // rawBody must be the exact bytes received, not a re-serialised object.export function verify(rawBody, signatureHeader, secret) { const expected = createHmac("sha256", secret).update(rawBody).digest("hex"); const given = Buffer.from(signatureHeader ?? "", "utf8"); const want = Buffer.from(expected, "utf8"); return given.length === want.length && timingSafeEqual(given, want);}Retries and failures
- A non-2xx response or a timeout counts as a failed delivery and is retried with exponential backoff over a bounded window. schedule subject to change
- Deliveries are idempotent by
id: store the ids you have processed and ignore repeats. - Every attempt is visible under Alerts → History with its status, so you can see what your endpoint returned.
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.