웹훅
RolChat은 서명된 HTTP POST 요청으로 여러분의 시스템에 이벤트를 전달합니다. 이 페이지는 플러그인 웹훅을 설명합니다. 자동화 규칙이 보내는 웹훅은 재시도, 대기 시간, 시크릿 교체 방식이 다릅니다. 자동화 웹훅을 참고하세요. 반대 방향, 즉 여러분의 시스템, 플러그인, 제공업체가 RolChat으로 보낼 때도 같은 규칙이 적용됩니다. 처리하기 전에 아래 순서대로 모든 전송을 검증하세요.
전송의 형태
섹션 제목: “전송의 형태”POST /your/endpoint HTTP/1.1Content-Type: application/jsonUser-Agent: RolChat-Webhook/1.0X-RolChat-Timestamp: 1713615825X-RolChat-Signature: sha256=a1b2c3…X-RolChat-Nonce: nonce_01HKQN9…X-RolChat-Event-Id: evt_01HKQN9…
{ "id": "evt_01HKQN9…", "type": "conversation.created", "occurred_at": "…", "data": { … } }| 헤더 | 의미 |
|---|---|
X-RolChat-Timestamp |
발송 시점의 Unix 초. 서명되는 메시지의 일부입니다. |
X-RolChat-Signature |
sha256=<hex>. 접두사가 알고리즘을 나타내므로 나중에 바뀔 수 있습니다. |
X-RolChat-Nonce |
이 HTTP 요청에 고유한 ULID. 재시도에는 새 논스가 붙습니다. |
X-RolChat-Event-Id |
이벤트 자체의 ID. 재시도해도 바뀌지 않으므로 중복 제거에 사용합니다. |
발신 전송은 HTTPS 엔드포인트로만 갑니다. HTTP URL은 구독을 만들 때 거부됩니다.
서명되는 메시지는 타임스탬프, 점 하나, 그리고 바이트 그대로의 원시 요청 본문입니다.
canonical = "<timestamp>.<body>"signature = hex( HMAC-SHA256( secret, canonical ) )받은 바이트에 서명하세요. 파싱한 JSON을 다시 직렬화한 사본이 아닙니다. 공백이나 키 순서가 바뀌면 서명이 맞지 않습니다. 허용되는 알고리즘은 SHA-256뿐입니다.
전송 검증하기
섹션 제목: “전송 검증하기”다음 다섯 가지 검사를 순서대로 하세요. Python, Node.js, Go, Ruby, PHP 예제는 검증 예제 페이지에 있습니다.
- 유효 시간.
|now − X-RolChat-Timestamp| > 300초이면 거부합니다(400). 5분이면 시계 오차를 허용하면서, 그 이후에는 가로챈 요청을 쓸모없게 만듭니다. 서버 시간은 NTP로 맞춰 두세요. - 서명. 기대값을 계산하고 상수 시간 비교(
hmac.compare_digest,crypto.timingSafeEqual,hash_equals)로 비교합니다. 일치하지 않으면401로 거부합니다. 일반 문자열 비교는 타이밍 정보가 새므로 허용되지 않습니다. - 논스. 원자적인 “없을 때만 설정”(
SET NX EX 600)으로X-RolChat-Nonce를 10분 TTL로 저장합니다. 이미 있으면409로 거부합니다. 재전송된 요청입니다. 논스 저장소가 중단되었다면 RolChat이 재시도하도록503으로 안전하게 실패하세요. 절대 “수락”으로 넘어가지 마세요. - 본문 파싱은 이 단계에서 처음 합니다.
- 이벤트 ID로 중복 제거. 재시도에는 새 논스가 붙지만
X-RolChat-Event-Id는 같습니다. 최근 7일 안에 그 ID를 처리했다면 다시 처리하지 않고200으로 응답합니다.
전송을 안전하게 받아들였다면 곧바로 2xx로 응답하고, 작업은 비동기로 처리하세요. RolChat은 응답을 15초 동안 기다립니다.
비밀 값
섹션 제목: “비밀 값”- 웹훅 비밀 값은 base64url로 인코딩된 64바이트 난수(약 86자)입니다. 구독이나 플러그인을 만들 때 생성되며 한 번만 표시됩니다.
- 자체 보관소나 환경 변수에 저장하세요. RolChat은 암호화된 사본만 보관합니다.
- 90일 후 교체를 권장합니다. 제품이 알림을 보여 주지만, 교체하지 않았다고 구독을 비활성화하지는 않습니다.
- 교체에는 겹치는 기간이 있습니다.
POST /api/v1/plugins/{id}/webhook-secret/rotate후 7일 동안은 이전 비밀 값과 새 비밀 값 모두 검증을 통과하고, 새 전송은 새 비밀 값으로 서명되며, 이전 비밀 값은 기간이 끝나면 삭제됩니다. 교체하는 순간 아무것도 깨지지 않습니다. - 비밀 값이 유출되면
POST /api/v1/plugins/{id}/webhook-secret/revoke가 즉시 무효화하고, 새 비밀 값을 발급하고, 계정 관리자에게 이메일을 보내고, 감사 항목을 기록합니다.
재시도와 데드 레터
섹션 제목: “재시도와 데드 레터”2xx가 아닌 응답이나 네트워크 오류가 있으면 재시도가 예약됩니다.
| 시도 | 이전 시도 후 지연 |
|---|---|
| 1 | 즉시 |
| 2 | 15초 |
| 3 | 1분 |
| 4 | 5분 |
| 5 | 30분 |
| 6 | 2시간 |
| 7 | 8시간 |
| 8 | 24시간 |
408, 429, 5xx와 네트워크 오류는 재시도됩니다. 400, 401, 403, 404, 410은 재시도되지 않고 곧바로 데드 레터 큐로 갑니다. 거부된 서명이나 없는 엔드포인트에 재시도해도 소용이 없기 때문입니다. 여덟 번 실패한 전송도 데드 레터가 됩니다.
데드 레터는 30일 동안 보관되며 설정 → 플러그인 → {플러그인} → 웹훅 로그 → DLQ에서 볼 수 있고, 관리자는 거기서 다시 보낼 수 있습니다(POST /api/v1/plugins/{id}/webhook-dlq/{entry_id}/replay).
- 발신 본문: 기본 1 MB(플러그인별로 설정 가능). RolChat으로 들어오는 본문: 5 MB. 더 크면
413입니다. - 플러그인은
allowed_source_ips를 선언할 수 있으며, RolChat은 검증 전에 그 허용 목록을 적용합니다. - 추가적인 타당성 확인으로
RolChat-Webhook/1.0사용자 에이전트를 확인할 수 있습니다. 이는 보안 통제 수단이 아닙니다.
RolChat으로 들어오는 웹훅
섹션 제목: “RolChat으로 들어오는 웹훅”제공업체는 자체 서명 방식(Twilio, Telnyx, Bandwidth, WhatsApp의 경우 Meta, Stripe)으로 /api/v1/webhooks/{category}/{adapter}에 RolChat으로 보냅니다. 각 어댑터는 제공업체의 서명을 검증하고, 페이로드를 정규화하고, RolChat 서명과 함께 내부 이벤트 버스에 다시 게시합니다. 여러분의 시스템도 위에서 설명한 X-RolChat-* 헤더를 사용하고, 해당 엔드포인트를 소유한 플러그인의 비밀 값으로 서명해 RolChat으로 보낼 수 있습니다.
자동화 웹훅
섹션 제목: “자동화 웹훅”자동화 모듈의 HTTP 요청 보내기 작업에는 자체 전송 규칙이 있습니다.
- 계정당 시크릿 하나. 자동화 화면에서 확인하거나 교체합니다(소유자와 관리자). 교체는 즉시 적용됩니다. 겹치는 기간이 없고 이전 시크릿은 곧바로 검증되지 않으므로, 수신 측을 먼저 업데이트하거나 짧은 공백을 감수하세요.
- 대기 시간: RolChat은 응답을 10초 기다립니다.
- 재시도: 총 최대 6번 시도합니다. 2번째 시도 전의 간격은 30초이며, 이후 약 2분, 8분, 32분, 2시간 8분으로 늘어나고 매번 최대 20 % 변동합니다. 한 번의 간격이 6시간을 넘지 않습니다.
- 재시도 대상: 네트워크 오류, 시간 초과,
5xx,408,425,429. 그 밖의4xx응답, 차단된 주소, 너무 큰 본문은 재시도하지 않습니다. 이 전송은 마지막 시도가 실패했을 때와 마찬가지로 곧바로 데드 레터 큐로 들어갑니다. - 헤더:
X-RolChat-Signature,X-RolChat-Signature-V2,X-RolChat-Timestamp,X-RolChat-Delivery-Id,X-RolChat-Attempt.
수신기 테스트하기
섹션 제목: “수신기 테스트하기”POST /api/v1/webhooks/test-signature는 호출한 플러그인의 엔드포인트로 서명된 합성 이벤트를 보내, 실제 트래픽이 오기 전에 구현을 처음부터 끝까지 검증할 수 있게 합니다.
흔한 실수
섹션 제목: “흔한 실수”- 원시 바이트가 아니라 파싱 후 다시 인코딩한 JSON으로 검증하기.
==로 서명 비교하기.- 이벤트 ID가 아니라 논스로 중복 제거하기(재시도마다 논스가 새로 바뀝니다).
- 시계가 5분 넘게 어긋나 있기.
- 응답하기 전에 오래 걸리는 작업을 해서 15초에 시간 초과되고 같은 이벤트를 다시 받기.