웹훅 (Webhook)
웹훅이란?
웹훅(Webhook)은 메일리에서 특정 이벤트가 발생했을 때, 미리 등록해 둔 URL로 실시간 HTTP POST 요청을 보내주는 기능입니다. 구독자가 새로 등록되거나, 유료 멤버십에 진입하거나, 뉴스레터가 발행되는 순간 외부 시스템에 자동으로 알림을 전달할 수 있습니다.
예를 들어 새 구독자가 등록될 때마다 CRM에 연락처를 추가하거나, 구독 취소 시 내부 슬랙 채널에 알림을 보내는 등 다양한 자동화 워크플로우를 만들 수 있습니다.
웹훅은 마케팅 플랜 전용 기능입니다. 마케팅 플랜으로 업그레이드하면 웹훅 등록 및 관리 기능을 이용할 수 있습니다.
지원하는 이벤트
메일리에서 웹훅으로 수신할 수 있는 이벤트는 다음 다섯 가지입니다.
| 이벤트 | 발생 시점 |
|---|---|
| subscription.created | 새 구독자가 등록될 때 |
| subscription.canceled | 구독자가 구독을 취소할 때 |
| subscription.paid_started | 구독자가 최초로 유료 멤버십에 진입(결제)할 때 |
| subscription.paid_ended | 유료 멤버십이 종료되어 무료/취소 상태로 전환될 때 |
| post.published | 뉴스레터가 발행될 때 |
post.published는 일반 발행에만 전송됩니다. 숨김 발행(웹에는 게시하되 이메일은 보내지 않는 발행)에는 전송되지 않습니다.
웹훅 등록하기
- 좌측 메뉴 개발자 도구 → 웹훅으로 이동합니다.
- 새 웹훅 등록을 클릭합니다.
- 알림을 받을 Webhook URL을 입력합니다. (
https://로 시작하는 주소만 등록할 수 있습니다.) - 필요하면 설명을 입력합니다. (선택)
- 수신할 이벤트를 하나 이상 선택합니다.
- 웹훅 등록을 클릭해 저장합니다.
등록이 완료되면 Signing Secret이 자동으로 생성됩니다. 이 값은 웹훅 요청이 위조되지 않았는지 검증할 때 사용되므로 안전한 곳에 보관하세요.

웹훅 요청 구조
이벤트가 발생하면 등록된 URL로 아래와 같은 HTTP POST 요청이 전송됩니다.
요청 헤더
| 헤더 | 설명 |
|---|---|
| Content-Type | application/json 고정 |
| User-Agent | Maily-Webhook/1.0 고정 |
| X-Maily-Event | 발생한 이벤트 이름 (예: subscription.created) |
| X-Maily-Timestamp | 서명 생성 시각 (Unix timestamp, 초 단위) |
| X-Maily-Signature | HMAC-SHA256 서명값 (아래 서명 검증 참고) |
요청 본문(body)에는 이벤트 이름 없이 아래 이벤트별 필드가 최상위에 담깁니다. 이벤트 종류는 X-Maily-Event 헤더로 구분하세요.
이벤트별 Payload
subscription.created
새 구독자가 등록될 때 전송됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| subscription_id | String | 구독의 고유 식별자 |
| String | 구독자 이메일 주소 | |
| created_at | DateTime | 구독 생성 시각 (ISO 8601) |
subscription.canceled
구독자가 구독을 취소할 때 전송됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| subscription_id | String | 구독의 고유 식별자 |
| String | 구독자 이메일 주소 | |
| canceled_at | DateTime | 구독 취소 시각 (ISO 8601) |
| reason | String / null | 취소 사유 (입력하지 않은 경우 null) |
subscription.paid_started
구독자가 최초로 유료 멤버십 결제를 시작할 때 전송됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| subscription_id | String | 구독의 고유 식별자 |
| String | 구독자 이메일 주소 | |
| plan | String | 결제한 멤버십 플랜 (예: monthly, yearly) |
| amount | Number | 결제 금액 (원) |
| started_at | DateTime | 유료 멤버십 시작 시각 (ISO 8601) |
subscription.paid_ended
유료 멤버십이 종료되어 무료 또는 취소 상태로 전환될 때 전송됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| subscription_id | String | 구독의 고유 식별자 |
| String | 구독자 이메일 주소 | |
| previous_plan | String | 종료 전 플랜 |
| current_plan | String | 전환된 플랜 (free, canceled 등) |
| ended_at | DateTime | 유료 멤버십 종료 시각 (ISO 8601) |
post.published
뉴스레터가 발행될 때 전송됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
| post_id | String | 뉴스레터의 고유 식별자 |
| title | String | 뉴스레터 제목 |
| published_at | DateTime | 발행 시각 (ISO 8601) |
서명 검증 (Signature Verification)
웹훅 요청이 메일리에서 보낸 것인지 확인하려면 X-Maily-Signature 헤더값을 검증하세요. 이를 통해 제3자가 위조한 요청을 걸러낼 수 있습니다.
검증 절차
- 요청의
X-Maily-Timestamp헤더값과 요청 본문(body)을 마침표(.)로 이어{timestamp}.{body}문자열을 만듭니다. - 이 문자열을 웹훅의 Signing Secret을 키로 하여 HMAC-SHA256으로 서명하고 16진수(hex) 문자열로 변환합니다.
- 계산한 값이
X-Maily-Signature헤더값과 같으면 정상 요청입니다.
코드 예시
재시도 정책 및 자동 비활성화
웹훅 전송이 실패하면 메일리가 자동으로 재시도합니다. 안정적인 연동을 위해 아래 정책을 참고하세요.
| 항목 | 내용 |
|---|---|
| 성공 기준 | HTTP 2xx 응답 |
| 요청 타임아웃 | 연결·응답 각각 10초 |
| 재시도 횟수 | 한 이벤트당 최대 3회 (간격은 재시도할수록 점진적으로 증가) |
| 자동 비활성화 | 연속 10회 실패 시 해당 웹훅이 자동으로 비활성화 |
연속 실패로 비활성화된 웹훅은 개발자 도구 → 웹훅 → 상세 → 수정에서 활성화에 체크해 다시 켤 수 있습니다. 다시 켜기 전에 수신 서버 상태를 먼저 확인하세요.
테스트 발송
실제 이벤트를 발생시키지 않고도 웹훅 연동을 테스트할 수 있습니다.
- 개발자 도구 → 웹훅에서 테스트할 웹훅을 클릭해 상세로 들어갑니다.
- 상단의 테스트 발송 버튼을 클릭합니다.
- 등록된 각 이벤트에 대해 샘플 payload가 등록한 URL로 전송됩니다.
웹훅이 비활성 상태이면 테스트 발송이 실제로 전송되지 않습니다. 먼저 웹훅을 활성화한 뒤 테스트하세요.
활용 사례
- CRM 연동 — 새 구독자를 자동으로 고객 목록에 추가
- 슬랙/디스코드 알림 — 구독·취소·발행 이벤트를 팀 채널로 실시간 알림
- 이탈 분석 — 구독 취소 이벤트를 수집해 사유 분석
- 멤버십 관리 — 유료 멤버십 시작/종료를 외부 시스템과 동기화
- 크로스 포스팅 — 뉴스레터 발행 시 다른 채널에 자동 게시
자주 묻는 질문
HTTP는 안 되고 HTTPS만 되나요?
네, 보안을 위해 https://로 시작하는 URL만 등록할 수 있습니다. 개발 환경에서 테스트할 때는 ngrok 같은 터널링 도구를 사용하면 로컬 서버에서도 HTTPS로 수신할 수 있습니다.
하나의 이벤트에 여러 웹훅을 등록할 수 있나요?
네, 같은 이벤트를 수신하는 웹훅을 여러 개 등록할 수 있습니다. 각 웹훅은 독립적으로 동작하며, 이벤트가 발생하면 그 이벤트를 구독한 모든 활성 웹훅으로 요청이 전송됩니다.
웹훅 요청에 어떻게 응답해야 하나요?
HTTP 2xx 상태 코드(예: 200 OK)를 반환하면 성공으로 처리됩니다. 그 외 응답 코드나 타임아웃(10초)은 실패로 간주되어 재시도 대상이 됩니다. 가능한 한 빠르게 응답을 반환하고, 오래 걸리는 작업은 비동기로 처리하는 것을 권장합니다.
Signing Secret을 변경할 수 있나요?
등록 시 자동으로 생성되며, 직접 변경(재발급)하는 기능은 지원하지 않습니다. Secret이 노출되었다면 해당 웹훅을 삭제하고 새로 등록하면 새로운 Secret이 발급됩니다.