웹훅 수신
서명 및 멱등성을 갖춘 범용 웹훅, WhatsApp, Linq, WATI, Nextcloud Talk, Gmail 푸시, SOP 웹훅.
게이트웨이는 외부 시스템이 에이전트로 메시지를 전송할 수 있는 공개 HTTP 수신 경로 세트를 제공합니다. 이 경로들은 Bearer 인증 방식의 /api/* 엔드포인트와는 별개입니다. 각 웹훅은 해당 플랫폼에 맞게 조정된 공유 시크릿, HMAC 서명, 또는 프로바이더 허브 핸드셰이크 등 자체 인증 방식을 사용합니다. 이 엔드포인트를 사용해 메시징 프로바이더, 이메일 푸시 구독, 또는 서드파티 시스템을 일반 HTTP POST를 통해 Revka에 연결하세요.
웹훅으로 메시지를 전달하는 채널(WhatsApp Cloud API, WATI, Linq, Nextcloud Talk, Gmail 푸시)을 설정하거나, 범용 통합 엔드포인트를 노출하거나, 인바운드 HTTP 이벤트로부터 표준 운영 절차를 실행할 때 이 페이지를 참조하세요. 모든 웹훅 채널은 공개적으로 접근 가능한 HTTPS URL이 필요합니다 — 시작하기 전에 터널로 게이트웨이 노출하기를 먼저 확인하세요. 각 통합의 채널 설정은 채널 개요를, Bearer 인증 REST 엔드포인트에 대해서는 게이트웨이 API 개요를 참조하세요.
범용 웹훅
섹션 제목: “범용 웹훅”가장 단순한 통합 방법입니다. JSON message를 POST하면 게이트웨이가 이를 에이전트 턴으로 실행합니다.
POST /webhookContent-Type: application/json{ "message": "Hello agent" }message 필드는 필수입니다. 다른 JSON 형식을 전송하면 400을 반환합니다. 응답에는 에이전트의 답변이 포함됩니다.
범용 웹훅은 두 개의 독립적이고 중첩 가능한 계층으로 보호됩니다.
- 페어링 Bearer 토큰.
[gateway].require_pairing = true(기본값)인 경우,/webhook은 나머지 API와 동일한Authorization: Bearer rk_<token>을 요구합니다. 페어링되지 않았거나 유효하지 않은 토큰은401을 반환합니다. 신뢰할 수 있는 머신의 localhost에 바인딩된 게이트웨이에만require_pairing = false를 설정하세요. - 웹훅 시크릿 (선택 사항). 웹훅 시크릿이 구성된 경우, 호출자는
X-Webhook-Secret헤더에도 이를 전송해야 합니다. 구성된 시크릿은 시작 시 SHA-256으로 해시되며 평문으로는 저장되지 않습니다. 수신된 헤더는 해시된 후 상수 시간으로 비교됩니다. 값이 없거나 올바르지 않으면401을 반환합니다.
POST /webhookAuthorization: Bearer rk_<token>X-Webhook-Secret: <shared-secret>X-Idempotency-Key: 3f1c… # optional, see IdempotencyX-Session-Id: ops-room # optional, scopes the agent turnContent-Type: application/json
{ "message": "Summarize today's incidents" }| 헤더 | 필수 여부 | 설명 |
|---|---|---|
Authorization: Bearer | 페어링이 필요한 경우 | 페어링 토큰 (페어링 및 인증 참조) |
X-Webhook-Secret | 시크릿이 설정된 경우 | 공유 시크릿, SHA-256 해시로 상수 시간 비교 |
X-Idempotency-Key | 아니오 | TTL 창 내에서 재전송된 요청을 중복 제거 |
X-Session-Id | 아니오 | 대화 연속성을 위해 턴을 명명된 세션으로 라우팅 |
curl -X POST https://<gateway>/webhook \ -H "Authorization: Bearer rk_<token>" \ -H "X-Webhook-Secret: <shared-secret>" \ -H "Content-Type: application/json" \ -d '{"message": "Hello agent"}'WhatsApp 웹훅
섹션 제목: “WhatsApp 웹훅”Meta의 WhatsApp Cloud API는 웹훅을 통해 메시지를 전달합니다. 게이트웨이는 인증 핸드셰이크와 메시지 전달 모두를 처리합니다.
GET /whatsapp # Meta hub verification challengePOST /whatsapp # inbound message deliveryGET 핸들러는 hub.mode, hub.verify_token, hub.challenge 쿼리 파라미터를 사용해 Meta의 구독 핸드셰이크에 응답합니다. hub.verify_token이 구성된 verify_token과 일치하면 게이트웨이는 hub.challenge를 반환합니다. POST 핸들러는 X-Hub-Signature-256 헤더의 페이로드 HMAC을 앱 시크릿으로 검증한 후 메시지를 에이전트로 라우팅합니다.
채널을 [channels_config.whatsapp] 아래에 구성하세요.
[channels_config.whatsapp]access_token = "EAAB…"phone_number_id = "123456789012345"verify_token = "your-verify-token"app_secret = "your-app-secret"allowed_numbers = ["*"]| 필드 | 설명 |
|---|---|
access_token | Cloud API 액세스 토큰 (필수) |
phone_number_id | Cloud API 모드 활성화 (필수) |
verify_token | GET 핸드셰이크 시 hub.verify_token과 비교 (필수) |
app_secret | X-Hub-Signature-256 검증을 위한 HMAC 키; REVKA_WHATSAPP_APP_SECRET 환경 변수로도 설정 가능 |
allowed_numbers | 에이전트에 메시지를 보낼 수 있는 E.164 번호 목록; ["*"]는 모두 허용 |
Meta 콜백 URL을 https://<gateway>/whatsapp으로 설정하세요. 앱 시크릿이 구성되지 않은 경우 HMAC 검증이 생략됩니다(테스트/개발 환경 전용 — 프로덕션에서는 반드시 설정하세요). Cloud API와 WhatsApp Web 모드에 대해서는 WhatsApp (Cloud API & Web)을 참조하세요.
Linq 웹훅
섹션 제목: “Linq 웹훅”Linq의 Partner API는 웹훅을 통해 iMessage, RCS, SMS 메시지를 전달합니다.
POST /linq서명 시크릿이 구성된 경우 핸들러는 HMAC-SHA256 서명을 검증하며, 타임스탬프가 300초 이상 오래된 요청은 거부합니다(재전송 공격 방지). 자체 전송 메시지(is_from_me / 아웃바운드 방향)는 에이전트가 자기 자신에게 응답하지 않도록 필터링됩니다.
[channels_config.linq]api_token = "linq-partner-api-token"from_phone = "+15551234567"signing_secret = "optional-signing-secret"allowed_senders = ["*"]| 필드 | 설명 |
|---|---|
api_token | Linq Partner API 토큰 (필수) |
from_phone | E.164 발신자 번호 (필수) |
signing_secret | HMAC 서명 시크릿; REVKA_LINQ_SIGNING_SECRET 환경 변수로 재정의 가능 |
allowed_senders | 에이전트에 메시지를 보낼 수 있는 E.164 번호 목록; ["*"]는 모두 허용 |
Linq 대시보드에서 웹훅 URL을 https://<gateway>/linq로 설정하세요. 이메일, iMessage, Linq & 자동화를 참조하세요.
WATI 웹훅
섹션 제목: “WATI 웹훅”WATI는 WhatsApp Business API를 호스팅하며 웹훅을 통해 메시지를 전송합니다.
GET /wati # endpoint verificationPOST /wati # inbound message delivery인바운드 메시지는 allowed_numbers를 통해 필터링됩니다. [transcription]이 활성화된 경우 오디오 첨부 파일이 텍스트로 변환되며, 미디어 다운로드는 미디어 호스트가 구성된 api_url 호스트와 일치하도록 요구하여 SSRF를 방지합니다.
[channels_config.wati]api_token = "wati-bearer-token"api_url = "https://live-mt-server.wati.io"tenant_id = "my-tenant"allowed_numbers = ["*"]| 필드 | 설명 |
|---|---|
api_token | WATI Bearer 토큰 (필수) |
api_url | WATI API 기본 URL (필수) |
tenant_id | 수신자 타겟팅을 위한 선택적 테넌트 접두사 |
allowed_numbers | 에이전트에 메시지를 보낼 수 있는 E.164 번호 목록; ["*"]는 모두 허용 |
다른 지역 플랫폼과 함께 WATI를 알아보려면 Lark, Feishu, DingTalk, WeCom, QQ & Mochat을 참조하세요.
Nextcloud Talk 웹훅
섹션 제목: “Nextcloud Talk 웹훅”Nextcloud Talk 봇은 웹훅으로 룸 메시지를 전달하며, 에이전트는 Talk OCS API를 통해 응답합니다.
POST /nextcloud-talk웹훅 시크릿이 구성된 경우 핸들러는 X-Nextcloud-Talk-Random과 X-Nextcloud-Talk-Signature 헤더를 사용해 HMAC-SHA256 서명을 검증하며, 유효하지 않거나 오래된 요청은 401로 거부됩니다. 봇 자신의 메시지는 자기 반향을 방지하기 위해 봇 이름 매칭으로 필터링됩니다.
[channels_config.nextcloud_talk]base_url = "https://cloud.example.com"app_token = "nextcloud-talk-app-token"bot_name = "revka"webhook_secret = "optional-webhook-secret"allowed_users = ["*"]| 필드 | 설명 |
|---|---|
base_url | Nextcloud 인스턴스 URL (필수) |
app_token | Talk 봇 앱 토큰 (필수) |
bot_name | 자기 반향 필터링에 사용되는 표시 이름 (기본값: 빈 값 — 설정 전까지 이름 기반 자기 반향 필터링 없음) |
webhook_secret | HMAC 서명 시크릿; REVKA_NEXTCLOUD_TALK_WEBHOOK_SECRET 환경 변수로 재정의 가능 |
allowed_users | 에이전트에 메시지를 보낼 수 있는 Nextcloud 사용자 ID 목록; ["*"]는 모두 허용 |
봇의 웹훅을 https://<gateway>/nextcloud-talk으로 설정하세요. Matrix, Mattermost & Nextcloud Talk와 Mattermost & Nextcloud Talk 설정을 참조하세요.
Gmail Pub/Sub 푸시 웹훅
섹션 제목: “Gmail Pub/Sub 푸시 웹훅”IMAP 폴링 대신, Gmail은 Google Cloud Pub/Sub에 알림을 푸시할 수 있으며, Pub/Sub는 이를 웹훅으로 전달합니다. 게이트웨이는 푸시를 수신하고 Gmail History API를 사용해 새 메시지를 가져옵니다.
POST /webhook/gmail이 웹훅은 다른 웹훅과 다르게 인증합니다. 웹훅 시크릿이 구성된 경우, 요청은 Authorization 헤더에 Bearer 토큰으로 시크릿을 전달해야 합니다(Authorization: Bearer <webhook_secret>). 이는 Pub/Sub 푸시 구독에 설정하는 공유 시크릿이며, 페어링 토큰이 아닙니다. Gmail 푸시가 활성화되지 않은 경우 404를, 본문이 크기 제한을 초과하는 경우 413을 반환합니다.
[channels_config.gmail_push]enabled = truetopic = "projects/my-project/topics/gmail-topic"oauth_token = "" # or the GMAIL_PUSH_OAUTH_TOKEN env varlabel_filter = ["INBOX"]allowed_senders = ["*"]webhook_url = "https://<gateway>/webhook/gmail"webhook_secret = "" # or the GMAIL_PUSH_WEBHOOK_SECRET env var| 필드 | 설명 |
|---|---|
enabled | 채널을 등록하려면 true로 설정 (기본값 false) |
topic | GCP Pub/Sub 토픽 경로 (필수) |
oauth_token | Gmail API OAuth2 토큰; GMAIL_PUSH_OAUTH_TOKEN으로 대체 가능 |
label_filter | 감시할 Gmail 레이블 (기본값 ["INBOX"]) |
webhook_url | Pub/Sub 푸시 구독에 등록된 공개 URL |
webhook_secret | 푸시 요청이 제시해야 하는 Bearer 시크릿; GMAIL_PUSH_WEBHOOK_SECRET으로 대체 가능 |
설정에는 GCP 프로젝트, Pub/Sub 토픽이 필요하며, [email protected]에 Pub/Sub Publisher 역할을 부여해야 합니다. 감시 구독은 7일 만료 전에 자동 갱신됩니다. Gmail 계정의 IMAP 이메일 채널을 보완하거나 대체하는 용도로 사용하세요.
SOP 웹훅 엔드포인트
섹션 제목: “SOP 웹훅 엔드포인트”표준 운영 절차는 인바운드 웹훅으로 트리거될 수 있습니다. 위의 채널 웹훅과 달리, SOP 웹훅 트리거는 별도로 등록된 HTTP 라우트가 아닙니다 — SOP 엔진이 수신 웹훅 이벤트와 매칭하여 잠금, 감사, 쿨다운 메커니즘을 통해 디스패치하는 path입니다.
SOP의 SOP.toml에 웹훅 트리거를 선언하세요.
[[triggers]]type = "webhook"path = "/sop/deploy" # matched exactly against the incoming request path| 필드 | 설명 |
|---|---|
type | HTTP로 트리거되는 SOP에는 "webhook" |
path | 수신 웹훅 이벤트가 가져야 하는 완전 일치 경로 |
웹훅 이벤트가 path와 일치하면 엔진은 구성된 실행 모드(auto, supervised, step_by_step, priority_based, 또는 deterministic)로 SOP를 시작하며, cooldown_secs와 max_concurrent를 준수합니다. 여러 SOP가 동일한 path를 등록할 수 있으며, 일치하는 모든 SOP가 디스패치됩니다. 모든 실행 시작은 SOP 감사 로그에 기록됩니다.
SOP의 등록된 트리거를 사용하기 전에 확인하세요.
revka sop list # shows each SOP's triggers, e.g. "Triggers: webhook:/sop/deploy, manual"revka sop validate # validate all SOP definitions요청 서명
섹션 제목: “요청 서명”각 웹훅은 해당 플랫폼에서 사용하는 서명 방식을 따릅니다. 아래 표는 요청이 진본성을 증명하는 방법을 요약합니다.
| 엔드포인트 | 방식 | 시크릿 출처 |
|---|---|---|
POST /webhook | 페어링 Bearer 토큰, 선택적 X-Webhook-Secret (SHA-256, 상수 시간) | 페어링 흐름; 구성된 웹훅 시크릿 |
POST /whatsapp | X-Hub-Signature-256의 HMAC-SHA256 | app_secret 또는 REVKA_WHATSAPP_APP_SECRET |
POST /linq | HMAC-SHA256 + 300초 타임스탬프 신선도 | signing_secret 또는 REVKA_LINQ_SIGNING_SECRET |
POST /nextcloud-talk | X-Nextcloud-Talk-Random / X-Nextcloud-Talk-Signature에 대한 HMAC-SHA256 | webhook_secret 또는 REVKA_NEXTCLOUD_TALK_WEBHOOK_SECRET |
POST /webhook/gmail | Authorization: Bearer <webhook_secret> (공유 시크릿) | webhook_secret 또는 GMAIL_PUSH_WEBHOOK_SECRET |
GET /whatsapp, GET /wati | 프로바이더 허브 인증 핸드셰이크 | verify_token (WhatsApp) |
멱등성
섹션 제목: “멱등성”네트워크와 프로바이더는 재전송을 시도합니다. 범용 /webhook 엔드포인트는 인메모리 멱등성 저장소로 재전송을 중복 제거합니다. 안정적인 X-Idempotency-Key(예: UUID)를 전송하면 게이트웨이는 해당 키를 처음 받을 때만 에이전트를 실행합니다. TTL 창 내의 재전송은 에이전트를 재실행하지 않고 duplicate 본문과 함께 200을 반환합니다.
{ "status": "duplicate", "idempotent": true, "message": "Request already processed for this idempotency key"}게이트웨이 설정에서 저장소를 조정하세요.
[gateway]idempotency_ttl_secs = 300 # how long a key is rememberedidempotency_max_keys = 10000 # bounded cardinality; oldest keys evicted first| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
gateway.idempotency_ttl_secs | 정수 | 300 | 반복된 키가 중복으로 처리되는 창 |
gateway.idempotency_max_keys | 정수 | 10000 | 보유할 최대 고유 키 수; 오래된 키부터 제거 |
속도 제한
섹션 제목: “속도 제한”범용 /webhook 엔드포인트는 게이트웨이의 IP당 웹훅 속도 제한기(슬라이딩 창)로 보호됩니다. 프로바이더 웹훅(WhatsApp, Linq, WATI, Nextcloud Talk, Gmail)은 게이트웨이 수준에서는 속도 제한이 적용되지 않으며, 프로바이더 자체와 허용 목록 필터링에 의존합니다. 속도 제한기는 설정에서 조정할 수 있습니다.
[gateway]webhook_rate_limit_per_minute = 60 # 0 disables the webhook rate limitrate_limit_max_keys = 10000 # max tracked IP keys (LRU eviction)trust_forwarded_headers = false # see caution below| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
gateway.webhook_rate_limit_per_minute | 정수 | 60 | IP당 분당 요청 수; 0은 비활성화 |
gateway.rate_limit_max_keys | 정수 | 10000 | 제거 전 추적할 최대 IP 키 수 |
gateway.trust_forwarded_headers | 불리언 | false | 소켓 피어 대신 X-Forwarded-For / X-Real-IP를 속도 제한 기준으로 사용 |
제한 초과 요청은 retry_after 힌트와 함께 429 Too Many Requests를 반환합니다.
채널 이벤트 수신
섹션 제목: “채널 이벤트 수신”게이트웨이는 로컬 서비스가 구조화된 이벤트(에이전트 완료, 인간 승인 요청)를 연결된 SSE 및 WebSocket 구독자에게 브로드캐스트하고 Discord, Slack, Telegram으로 알림을 팬아웃하는 데 사용하는 내부 이벤트 수신 엔드포인트도 제공합니다.
POST /api/channel-events # localhost only — remote IPs receive 403{ "type": "human_approval_request", "content": { "title": "Deploy approval", "message": "Approve production deploy?" }, "channels": ["discord", "slack", "dashboard"], "run_id": "…", "step_id": "…", "approve_keywords": ["approve", "yes"], "reject_keywords": ["reject", "no"]}| 필드 | 설명 |
|---|---|
type | 이벤트 타입; "human_approval_request"는 특별히 처리됨 |
channels | 디스패치할 대상: "discord", "slack", "telegram", "dashboard" |
content.title / content.message | 알림 텍스트 |
run_id / step_id | 승인 요청 이벤트에 필수 |
approve_keywords / reject_keywords | 답변이 일치할 경우 승인을 처리하는 키워드 |
human_approval_request의 경우 게이트웨이는 SSE를 통해 요청을 브로드캐스트하고 승인 레지스트리에 등록합니다. approve_keywords/reject_keywords와 일치하는 Discord 또는 Slack 답변이 승인을 처리합니다. 이것은 워크플로우 승인 게이트의 인바운드 상대편입니다 — 워크플로우 & Architect API와 실행, 승인 & 체크포인트를 참조하세요.
다음 단계
섹션 제목: “다음 단계”- 메시징 채널 연결 — 웹훅으로 전달되는 채널의 엔드투엔드 설정.
- 터널로 게이트웨이 노출하기 — 프로바이더에게 공개 HTTPS URL 제공.
- 실시간: WebSocket, SSE & Live Canvas — 수신이 생성하는 이벤트 구독.
- 페어링 및 인증 — 범용 웹훅이 요구할 수 있는 Bearer 토큰.
- TLS, 속도 제한, WebAuthn & 정적 서빙 — 수신 표면 강화.