RoomScope

Última actualización

Webhooks

Una regla de alerta puede entregar a un endpoint HTTPS, además de dentro de la app, por correo y por Telegram. Cada entrega es un POST JSON firmado con el secreto del canal, que se muestra una sola vez al crear el canal.

Configurar un endpoint

  1. En el panel, abre Alertas → Reglas → Nueva regla, elige los tipos de evento y agrega un canal Webhook con tu URL HTTPS. Con una clave de API, envía la misma regla a POST /v1/alerts/rules (alcance webhook:manage).
  2. Copia el secreto de firma (whsec_…). Se devuelve una sola vez, en webhookSecrets[].signingSecret, uno por cada canal de webhook. Guárdalo junto con tu endpoint.
  3. Responde con un 2xx en menos de 10 segundos y procesa el trabajo de forma asíncrona. No se siguen redirecciones, y se rechazan las direcciones privadas, de loopback o link-local.
  4. POST /v1/alerts/rules/{id}/test envía una entrega de ejemplo de tipo envelope (sourceEventId empieza por test_) para que puedas probar tu handler.

Eventos

Una regla indica en eventTypes los tipos de evento a los que reacciona; una lista vacía coincide con todos los tipos. Estos son los tipos que vale la pena alertar:

TipoSe activa cuando
envelopeSe observó un cofre del tesoro en una sala monitoreada. Se aplica el valor mínimo en diamantes de la regla.
goodyBagSe observó una goody bag en una sala monitoreada. Se aplica el valor mínimo en diamantes de la regla.
giftSe envió un regalo en una sala monitoreada. Se activa con cada regalo: el valor mínimo en diamantes no se aplica.

minDiamondCount vale 49 de forma predeterminada y, junto con un mínimo de 1.51 diamantes por espectador, filtra solo los cofres del tesoro y las goody bags. Los eventos de inicio y fin de LIVE todavía no se entregan.

Encabezados

EncabezadoValor
content-typeapplication/json
x-roomscope-alert-id<ruleId>:<eventId>, el mismo valor que alertId en el cuerpo. Usa este valor para eliminar duplicados.
x-roomscope-timestampHora Unix en segundos en que se firmó este intento.
x-roomscope-schema-versionVersión del esquema del payload, actualmente 2026-11-03 (agrega `links`).
x-roomscope-signaturesha256=<HMAC-SHA256 en hex de "<timestamp>.<raw body>">.

Payload

Un evento por solicitud, en JSON compacto. diamondCount, peopleCount y unpackAt (segundos Unix) se completan para envelope y goodyBag, y son null para los demás tipos.

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.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"}

Verificar firmas

La firma es un HMAC-SHA256, con el secreto whsec_… completo como clave, calculado sobre el encabezado de timestamp, un punto y el cuerpo sin procesar: <timestamp>.<body>. El digest en hexadecimal se envía como sha256=<hex> en x-roomscope-signature. Compara en tiempo constante y rechaza los timestamps fuera de una ventana que tú elijas (cinco minutos en el ejemplo de abajo) para evitar ataques de repetición.

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);}
Usa el cuerpo sin procesar
Analiza el JSON solo después de comprobar la firma, y calcula el HMAC sobre los bytes exactos que recibiste. Volver a serializar el objeto cambia los espacios y el escapado, y hace que la comparación falle.

Reintentos y fallas

  • Un estado menor que 300 es un éxito. Un 5xx, 408, 429, un error de red o un tiempo de espera agotado se reintentan; cualquier otro 4xx o un 3xx es una falla permanente.
  • Una entrega tiene como máximo 4 intentos, enviados uno tras otro sin espera. Cada intento se vuelve a firmar, así que deliveredAt, el timestamp y la firma cambian. Elimina duplicados según alertId, no según el cuerpo.
  • Después de una entrega exitosa, el mismo alertId no se vuelve a entregar durante 7 días.
  • Cada webhook entregado cuesta 1 crédito. Un espacio de trabajo puede recibir hasta 100,000 webhooks por mes calendario (UTC); las entregas que superen esa cifra se descartan.
  • Las entregas fallidas todavía no aparecen en el panel. Registra las solicitudes que recibes si necesitas un registro de auditoría.

Telegram y correo

La misma regla también puede entregar a un chat de Telegram conectado o a una dirección de correo; esos canales no requieren manejar firmas. Conecta Telegram desde Alertas → Canales.

¿Te resultó útil esta página?