콘텐츠로 이동

웹훅

RolChat은 서명된 HTTP POST 요청으로 여러분의 시스템에 이벤트를 전달합니다. 이 페이지는 플러그인 웹훅을 설명합니다. 자동화 규칙이 보내는 웹훅은 재시도, 대기 시간, 시크릿 교체 방식이 다릅니다. 자동화 웹훅을 참고하세요. 반대 방향, 즉 여러분의 시스템, 플러그인, 제공업체가 RolChat으로 보낼 때도 같은 규칙이 적용됩니다. 처리하기 전에 아래 순서대로 모든 전송을 검증하세요.

POST /your/endpoint HTTP/1.1
Content-Type: application/json
User-Agent: RolChat-Webhook/1.0
X-RolChat-Timestamp: 1713615825
X-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 예제는 검증 예제 페이지에 있습니다.

  1. 유효 시간. |now − X-RolChat-Timestamp| > 300초이면 거부합니다(400). 5분이면 시계 오차를 허용하면서, 그 이후에는 가로챈 요청을 쓸모없게 만듭니다. 서버 시간은 NTP로 맞춰 두세요.
  2. 서명. 기대값을 계산하고 상수 시간 비교(hmac.compare_digest, crypto.timingSafeEqual, hash_equals)로 비교합니다. 일치하지 않으면 401로 거부합니다. 일반 문자열 비교는 타이밍 정보가 새므로 허용되지 않습니다.
  3. 논스. 원자적인 “없을 때만 설정”(SET NX EX 600)으로 X-RolChat-Nonce를 10분 TTL로 저장합니다. 이미 있으면 409로 거부합니다. 재전송된 요청입니다. 논스 저장소가 중단되었다면 RolChat이 재시도하도록 503으로 안전하게 실패하세요. 절대 “수락”으로 넘어가지 마세요.
  4. 본문 파싱은 이 단계에서 처음 합니다.
  5. 이벤트 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 사용자 에이전트를 확인할 수 있습니다. 이는 보안 통제 수단이 아닙니다.

제공업체는 자체 서명 방식(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초에 시간 초과되고 같은 이벤트를 다시 받기.