최종 업데이트
Webhook
알림 규칙은 앱 내 알림, 이메일, Telegram과 함께 HTTPS 엔드포인트로도 전송할 수 있습니다. 모든 전송은 채널의 secret으로 서명된 JSON POST이며, 이 secret은 채널을 만들 때 한 번만 표시됩니다.
엔드포인트 설정
- 대시보드에서 알림 → 규칙 → 새 규칙을 열고 이벤트 유형을 선택한 뒤 HTTPS URL로 Webhook 채널을 추가하세요. API key를 사용한다면 같은 규칙을
POST /v1/alerts/rules(스코프webhook:manage)로 보내세요. - 서명 secret(
whsec_…)을 복사하세요. 이 값은 webhook 채널마다 하나씩webhookSecrets[].signingSecret에 한 번만 반환됩니다. 엔드포인트와 함께 보관하세요. - 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진수 값>. |
페이로드
요청 하나에 이벤트 하나가 압축된 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_… secret을 키로 사용해, 타임스탬프 헤더, 점, 원본 본문을 이어 붙인 값(<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는 영구 실패로 처리합니다. - 전송은 최대 4번 시도되며, 시도 사이에 지연 없이 연달아 보냅니다. 시도할 때마다 다시 서명하므로
deliveredAt, 타임스탬프, 서명이 바뀝니다. 본문이 아니라alertId로 중복을 제거하세요. - 전송에 성공한
alertId는 7일 동안 다시 전송되지 않습니다. - 전송된 webhook마다 1 크레딧이 듭니다. 워크스페이스는 달력 월(UTC)마다 최대 100,000개의 webhook을 받을 수 있으며, 이를 넘는 전송은 버려집니다.
- 실패한 전송은 아직 대시보드에 표시되지 않습니다. 감사 기록이 필요하면 수신한 요청을 직접 로그로 남기세요.
Telegram과 이메일
같은 규칙으로 연결된 Telegram 채팅이나 이메일 주소에도 전송할 수 있으며, 이 채널들은 서명을 처리할 필요가 없습니다. Telegram은 알림 → 채널에서 연결하세요.