웹훅과 이벤트
계정 웹훅은 계정 전체에서 일어나는 일(새 리드, 예약된 미팅, 단계가 바뀐 거래 등)을 내가 정한 URL로 실시간으로 보냅니다. Zapier와 n8n 연동도 내부적으로 이것을 사용하며, 내 엔드포인트로 보낼 수도 있습니다.
각 이메일의 응답 페이지에 있는 프로젝트 웹훅은 그대로 쓸 수 있습니다. 프로젝트 웹훅은 이메일 한 통의 상호작용만 다루고, 계정 웹훅은 모든 이메일과 아래 이벤트를 다룹니다. 서명 방식은 같습니다.
웹훅 추가하기
- 대시보드에서 개발자로 가서 웹훅 카드를 찾습니다.
- 엔드포인트 URL(공개된
https://URL)을 입력하고 원하는 이벤트를 선택합니다. - 웹훅 추가를 클릭하고 서명 시크릿을 복사합니다. 이번 한 번만 표시됩니다.
각 웹훅에는 만든 경로(대시보드, API, Zapier, n8n), 상태, 마지막 전달 시각이 표시됩니다. 테스트 보내기는 선택한 이벤트의 샘플을 data에 "test": true를 붙여 보냅니다. 삭제로 웹훅을 지웁니다. 계정당 최대 50개까지 만들 수 있습니다.
웹훅 추가와 삭제는 계정 소유자만 할 수 있으며, 먼저 다시 로그인하라는 요청을 받을 수 있습니다.
이벤트
| 이벤트 | 발생 시점 |
|---|---|
interaction.received | 수신자가 이메일에서 상호작용할 때(투표, 평가, 퀴즈 응답, 추적 클릭, 구매 등). 중복으로 걸러진 동작은 발생하지 않습니다. |
form.submitted | 이메일 속 양식(source: "email-form")이나 가입 양식(source: "signup-form")이 제출될 때. |
contact.created | 연락처가 목록에 추가될 때. |
contact.updated | 연락처의 필드가 바뀔 때. 같은 데이터를 다시 저장하면 발생하지 않습니다. |
lead.hot | 연락처의 참여도 점수가 핫 리드 기준값을 위로 넘을 때. |
lead.new | 가입 양식이나 이메일 속 양식으로 새 리드가 들어올 때. |
booking.created | 미팅이 예약될 때. |
booking.cancelled | 예약이 취소될 때(cancelledBy 포함). 일정 변경은 두 예약 이벤트 모두 발생시키지 않습니다. |
deal.created | 거래가 만들어질 때. 보드, 자동 규칙, 여정, 제안서, API 등 어디서든 해당됩니다. |
deal.stage_changed | 거래의 단계가 바뀔 때(성사와 실패 포함). |
purchase.completed | 수신자가 이메일 내 결제로 결제할 때. |
journey.completed | 연락처가 여정의 끝에 도달할 때. 중간에 나간 경우는 포함되지 않습니다. |
연락처 이벤트는 가져오기, 가입 양식, API, 동기화, AI 커넥터에서 발생합니다. 한 번에 500명을 넘는 연락처를 쓰는 경우(큰 CSV 가져오기 등)에는 발생하지 않으므로, 가져오기 한 번으로 워크플로가 수천 개 실행되지 않습니다. 연락처 표에서의 편집, 여정의 필드 업데이트 단계, 저장된 응답도 이 이벤트를 발생시키지 않습니다.
lead.hot과 lead.new는 리드 알림의 스위치나 제한과 상관없이 발생합니다. 구독하는 것 자체가 동의입니다.
페이로드
모든 전달은 같은 형식의 JSON POST입니다.
{
"id": "evt_8c1f…",
"type": "deal.stage_changed",
"createdAt": 1790000000000,
"data": {
"deal": {
"id": "deal_abc123",
"title": "Annual plan",
"value": 1200,
"currency": "USD",
"pipelineId": "owner_default",
"stageId": "proposal-sent",
"stage": "Proposal sent",
"status": "open",
"source": "manual",
"listId": "list_abc123",
"rowId": "3f6c1b0e2d…",
"email": "[email protected]"
},
"fromStageId": "meeting-booked"
}
}
id는 같은 이벤트의 모든 전달에서 같으며 X-MailInApp-Idempotency-Key 헤더로도 전달됩니다. 이미 처리한 재전달은 안전하게 버릴 수 있습니다. createdAt은 에포크 밀리초입니다.
이벤트 유형별 data 내용은 GET /api/v1/events/sample을 호출하거나 테스트 보내기로 확인하세요.
서명 검증하기
전달에는 X-MailInApp-Timestamp와 X-MailInApp-Signature 헤더가 붙으며, 프로젝트 웹훅과 똑같은 방식으로 계산됩니다. 서명 시크릿으로 원본 본문에 대해 검증하고, 몇 분 이상 지난 타임스탬프는 거부하세요. 바로 쓸 수 있는 Node.js 함수가 프로젝트 웹훅 문서에 있습니다.
재시도
엔드포인트는 5초 안에 2xx로 응답해야 합니다. 그 밖의 경우(시간 초과, 오류 상태, 리디렉션)는 실패로 처리되며, 같은 본문과 같은 멱등 키로 웹훅의 현재 URL에 간격을 늘려 가며 몇 시간 동안 자동으로 재시도합니다. 빠르게 응답하고, 오래 걸리는 작업은 그 뒤에 처리하세요.
- 엔드포인트가
410 Gone으로 응답하면 웹훅이 비활성화됩니다. REST Hooks 클라이언트는 이 방법으로 구독을 해지합니다. - API 키를 폐기하면 그 키로 만든 웹훅도 비활성화됩니다.
- 웹훅을 삭제하면 대기 중인 재시도도 멈춥니다.
API로 구독하기
Zapier, n8n, 내 코드는 API 키(Authorization: Bearer mia_live_…)로 웹훅을 관리할 수 있습니다.
curl https://mailinapp.com/api/v1/webhooks \
-H "Authorization: Bearer mia_live_..." \
-H "Content-Type: application/json" \
-d '{"url": "https://hooks.example.com/mailinapp", "events": ["lead.hot", "booking.created"]}'
201 응답에는 구독의 id와 모든 전달에 서명하는 secret이 들어 있습니다. 다시 반환되지 않으니 보관하세요. GET /api/v1/webhooks로 구독 목록을 보고, DELETE /api/v1/webhooks/{id}로 하나를 삭제합니다. 알 수 없는 이벤트 이름이 하나라도 있으면 요청 전체가 거부됩니다. 이 경로들은 키당 분당 30개 요청까지 허용합니다.
전체 규격은 OpenAPI 명세에 있습니다.