본문으로 건너뛰기

이벤트

ZeroTalk Outbound Webhook은 9개 이벤트를 전송합니다. 웹훅을 등록할 때 일부 이벤트만 구독할 수 있으며, 아무것도 고르지 않으면 전체를 구독합니다. PAT API로 등록할 때는 event_filters로 구독할 이벤트를 지정합니다.

노트

웹훅 이벤트는 고객 상담 채널(channel_type: user_chat)에서만 전송됩니다. 팀 채널 등 내부 채널의 이벤트는 전송되지 않습니다.

상담원의 내부 메모(sender_type가 internal인 이벤트)는 생성·수정·삭제 모두 웹훅으로 전송되지 않습니다.

이벤트 목록​

메시지​

이벤트설명
message.created새 메시지
message.updated메시지 수정
message.deleted메시지 삭제

채널​

고객 상담 채널(user_chat)의 상태 변화에만 발생합니다.

이벤트설명
channel.created채널 생성
channel.closed채널 종료
channel.reopened종료된 채널 재개
channel.assigned담당자 배정/변경
channel.snoozed대기 상태로 전환
channel.snooze_expired대기 만료

페이로드 구조​

웹훅 요청은 POST, Content-Type: application/json이며, 본문은 모든 이벤트가 동일한 envelope을 쓰는 JSON입니다.

{
"event_type": "message.created",
"workspace_id": "ws_abc123",
"timestamp": "2026-04-25T12:00:00.482Z",
"data": {
"message_id": "msg_def456",
"sender_id": "ct_xyz789",
"sender_type": "contact",
"sender_name": "방문자",
"content_type": "text",
"content": "안녕하세요",
"seq": 42,
"seq_timestamp": 1714032000000,
"created_at": "2026-04-25T12:00:00Z"
},
"channel": { "id": "ch_abc123" },
"contact": { "id": "ct_xyz789", "name": "방문자" }
}
필드설명
event_id이벤트의 고유 ID(문자열). 같은 이벤트를 재전송해도 값이 같으므로 중복 처리의 키로 쓸 수 있습니다. 자세한 내용은 중복 이벤트 걸러 내기를 참고하세요
event_type이벤트 종류
workspace_id발생 워크스페이스 ID
timestamp웹훅 전송(봉투 생성) 시각 (RFC 3339, UTC). 이벤트 발생 시각이 아니며, 같은 이벤트의 재전송 간에는 고정됩니다
data이벤트별 본문입니다. 키는 이벤트 종류에 따라 다릅니다(위 예시는 message.created)
contact·channel·assigned_member·integration관련 리소스의 스냅샷입니다. 해당 이벤트에 존재할 때만 포함되며, 없으면 키 자체가 생략됩니다. 전체 필드는 스냅샷 필드를 참고하세요. 위 예시는 channel과 contact의 일부 필드만 보여 줍니다
snake_case

모든 필드는 snake_case입니다 (event_type, workspace_id, channel_id 등).

data 키는 이벤트마다 다릅니다. 메시지 이벤트의 data.seq는 채널 내 메시지 순번(채널 단위로 증가, 워크스페이스 전역 순번 아님), data.seq_timestamp는 서버 발번 시각(밀리초)입니다. message.created의 data에는 위 예시 외에 attachments·metadata·seq_id·version도 있고(message.updated는 attachments·version, message.deleted는 version만), 채널 이벤트는 모두 version(채널 집계 버전)을 싣습니다.

발생 시각 필드는 일부 이벤트에만 있습니다 — created_at은 message.created·channel.created, deleted_at은 message.deleted, closed_at은 channel.closed에만 있습니다. message.updated는 상담원이 본문이나 첨부를 바꾼 수정일 때만 edited_at(수정 시각)이 있습니다. 나머지(그 밖의 message.updated·channel.reopened·channel.assigned·channel.snooze_expired)는 data에 발생 시각이 없습니다(channel.snoozed의 snoozed_until은 만료 예정 시각). 웹훅 전달 순서는 보장되지 않으니, 정렬·순서 처리는 전달의 순서 보장을 따르세요.

data에서 빠지는 식별자

봉투(envelope)나 스냅샷에 이미 있는 식별자는 중복을 피하려고 data에서 제거합니다. 제거하는 값은 workspace_id(항상 봉투에 있음)와, 해당 스냅샷이 포함될 때의 channel_id·contact_id·assigned_member_id·new_assigned_member_id입니다. 이 값들은 봉투나 스냅샷(channel.id·contact.id·assigned_member.id)에서 읽으세요. 따라서 채널 이벤트의 채널 ID는 channel.id 스냅샷에서 읽으면 됩니다. channel.created의 data에는 채널 ID가 id로도 남아 있지만 다른 채널 이벤트에는 없습니다. 메시지 이벤트는 data.message_id가 그대로 유지됩니다.

sender_type​

메시지의 data.sender_type은 다음 값 중 하나입니다.

값의미
member상담원
contact방문자·고객
system시스템 메시지. 워크플로우에서 고객이 한 동작(버튼 선택, 양식 제출, 이전 단계, 처음으로)과 통화 결과(종료·부재중·끊김·실패)만 전송합니다. 그 밖의 시스템 활동은 전송하지 않습니다
bot봇
workflow워크플로우 자동 발송
external외부 연동(공급자) 발송
integrationPublic API(PAT)로 전송된 메시지

integration 발신​

상담 콘솔이 Public API로 답장을 보내면(sender_member_id 없이) 그 메시지의 sender_type은 integration입니다. 상담원 쪽 UI에서는 member와 동일하게 상담원 측 메시지로 렌더링하고, 표시 이름은 메시지의 sender_name(토큰의 발신 신원 표시 이름, 지정하지 않았으면 API)을 사용하세요.

노트

data.sender_type이 internal인 상담원 내부 메모는 웹훅으로 전송되지 않습니다 (위 표에 없는 이유).

이벤트별 data​

data는 이벤트 종류마다 키가 다릅니다. 아래는 각 이벤트에서 실제로 받는 대표 필드입니다(위 data에서 빠지는 식별자 규칙 적용 후 기준).

노트

페이로드에는 문서에 없는 내부용 필드가 함께 올 수 있습니다. 모르는 필드는 무시하고 필요한 키만 읽도록 구현하세요(전방 호환).

메시지​

message.created​

새로 생성된 메시지. content는 미리보기가 아니라 전체 본문입니다.

{
"message_id": "msg_def456",
"sender_id": "ct_xyz789",
"sender_type": "contact",
"sender_name": "방문자",
"content_type": "text",
"content": "안녕하세요, 환불 문의드립니다.",
"attachments": [
{
"id": "att_01",
"type": "image",
"url": "https://cdn.example.com/a.png",
"name": "screenshot.png",
"size": 20480,
"mime_type": "image/png",
"thumbnail_url": "https://cdn.example.com/a_thumb.png"
}
],
"seq": 42,
"seq_timestamp": 1714032000000,
"created_at": "2026-04-25T12:00:00Z",
"parent_id": "msg_def000"
}
  • sender_type: 가능한 값은 위 sender_type 표 참고
  • content_type: text · markdown · image · file · card · button · video · audio · location · sticker · blocks 등
  • attachments: 첨부가 있을 때만 채워집니다
  • parent_id: 답글(스레드)인 경우에만
  • content_type이 blocks이면 구조화 본문이 blocks 키로 추가됩니다

message.updated​

메시지가 바뀌었을 때 발생합니다. 상담원의 수정뿐 아니라 전송 상태가 바뀔 때(예: 전송 실패)에도 발생합니다. 아래는 상담원이 본문을 고친 경우입니다.

{
"message_id": "msg_def456",
"sender_id": "mbr_111",
"sender_type": "member",
"content_type": "text",
"content": "수정된 전체 본문입니다.",
"is_last_message": true,
"version": 3,
"attachments": null,
"edited_by": "mbr_111",
"edited_at": "2026-10-06T08:12:02.123Z"
}
필드설명
attachments바뀐 뒤 메시지의 첨부 전체입니다. 형식은 message.created와 같고, 첨부가 없으면 null입니다
edited_by·edited_at상담원이 본문이나 첨부를 실제로 바꾼 수정에만 있습니다. 수정한 상담원 ID와 수정 시각입니다. 봇(AI) 답변을 상담원이 고친 경우 sender_type은 bot이고 edited_by가 고친 상담원입니다. 멘션만 바꾸거나 아무것도 바꾸지 않은 저장, 첨부 순서만 바꾼 저장, 전송 상태 변화에는 없습니다
changes본문 밖의 변화가 있을 때만 있습니다. 전송 상태(status·error_code 등)나, 본문은 그대로 두고 첨부·멘션만 바꾼 수정({"attachments": "updated"} 등)입니다. 본문 수정에는 changes가 없고 content에 새 본문이 실립니다

같은 메시지의 이벤트 순서는 version(메시지가 바뀔 때마다 증가)으로 판단하세요.

message.deleted​

메시지가 삭제됨. 본문(content) 없이 식별자와 시각만 옵니다.

{
"message_id": "msg_def456",
"deleted_at": "2026-04-25T12:05:00Z",
"is_last_message": false,
"actor_id": "mbr_111"
}
  • actor_id: 삭제를 수행한 주체(상담원 등). 시스템 삭제 등에서는 생략됩니다

채널​

채널 이벤트의 data는 대체로 작습니다 — 채널의 이름·상태·담당자 같은 맥락은 envelope의 channel·contact·assigned_member 스냅샷에서 읽으세요. version은 채널의 수정 버전 번호로, 이벤트 순서 판단이나 멱등 처리에 활용할 수 있습니다.

channel.created​

새 채널(상담)이 생성됨.

{
"id": "ch_abc123",
"channel_type": "user_chat",
"provider": "widget",
"status": "open",
"name": "지원 문의",
"is_private": false,
"tags": ["환불"],
"message_count": 0,
"assigned_type": "human",
"integration_id": "int_01",
"created_at": "2026-04-25T11:30:00Z"
}
  • assigned_type: human · ai · workflow
  • integration_id: 외부 채널(카카오·라인 등) 연동 채널일 때만

channel.closed​

채널이 종료됨.

{
"closed_at": "2026-04-25T13:00:00Z",
"version": 5
}

channel.reopened​

종료된 채널이 다시 열림. data에는 버전만 오고, 바뀐 상태는 channel 스냅샷(status: "open")에서 확인하세요.

{
"version": 6
}

channel.assigned​

담당자가 배정·변경·해제됨.

{
"previous_member_id": "mbr_111",
"new_assigned_member_id": null,
"assigned_type": "ai",
"version": 8
}
  • previous_member_id: 직전 담당자(없었으면 생략)
  • new_assigned_member_id: 새 담당자. 사람 담당자면 assigned_member 스냅샷의 id로 전달되어 여기선 제거되고, **담당 해제나 AI 배정이면 null**입니다
  • assigned_type: human(사람 배정) · ai(AI 배정). 담당 해제 시에는 생략됩니다

channel.snoozed​

채널이 대기(스누즈) 상태로 전환됨.

{
"snoozed_until": "2026-04-26T09:00:00Z",
"snooze_reason": "고객 회신 대기",
"version": 4
}
  • snooze_reason: 사유를 설정한 경우에만

channel.snooze_expired​

대기 기간이 만료되어 채널이 자동 재개됨. data에는 버전만 옵니다.

{
"version": 7
}

스냅샷 필드​

각 스냅샷의 주요 필드입니다 (해당 이벤트에서만 채워집니다).

  • contact: id, external_id, external_ids, name, is_name_auto_generated, email, phone, avatar_url, is_member, profile, created_at
  • channel: id, channel_type, provider, status, name, description, is_private, contact_id, contact_external_id, assigned_member_id, assigned_type, tags, message_count, metadata, created_at, integration_id(연동 채널만)
  • assigned_member: id, name, role, avatar_url, status
  • integration: id, provider, name

channel.tags가 반영되는 시점​

channel.tags는 ZeroTalk가 웹훅 페이로드를 만드는 시점에 조회한 태그입니다. 이벤트가 발생한 시점의 태그가 아닙니다. 태그를 붙이는 동작이 끝난 뒤에 만들어지는 페이로드부터 channel.tags에 그 태그가 들어갑니다. 태그가 하나도 없으면 tags 키 자체가 생략됩니다.

  • 같은 메시지에 반응한 워크플로우가 태그를 붙이는 경우: 워크플로우의 태그 부착과 그 메시지의 페이로드 생성은 처리 순서가 정해져 있지 않습니다. 그래서 그 메시지의 message.created 페이로드에 태그가 들어갈지는 보장하지 않습니다.
  • 재전송: 전달에 실패해 재전송하는 이벤트는 처음 만든 페이로드를 그대로 보냅니다. 재전송하는 동안 태그가 바뀌어도 channel.tags는 갱신되지 않습니다.
  • 태그 변경 자체는 이벤트가 아닙니다: 태그를 붙이거나 떼는 동작은 웹훅 이벤트를 보내지 않습니다. 태그가 필요하면 태그를 붙인 뒤 발생하는 이벤트의 channel.tags에서 확인하거나 API로 조회하세요.

고객 식별자 필드​

한 고객이 여러 채널로 문의하면 식별자를 여러 개 갖습니다. 두 대화가 같은 사람으로 확인되어 합쳐진 경우에도 마찬가지입니다.

필드의미
contact.external_id그 고객의 대표 식별자. 값이 바뀌지 않습니다
contact.external_ids그 고객이 응답하는 모든 식별자. external_id와 같은 표기
channel.contact_external_id이 대화가 들어온 식별자

세 필드 모두 없을 수 있습니다(omitempty). 웹 위젯 익명 방문처럼 식별자가 없는 고객, 그리고 식별자 기록 이전에 만들어진 대화가 그렇습니다.

연동하실 때: 고객을 자체 시스템과 대조한다면 external_id 하나만 보지 마시고 external_ids 전체에서 찾으세요. 대표 식별자만 보면, 합쳐지기 전에 다른 식별자로 문의하던 고객을 놓칩니다.

카카오 상담톡 유입 경로​

카카오 상담톡 대화는 channel.metadata에 고객이 어떤 경로로 상담을 시작했는지가 함께 옵니다.

키의미
kakao_started_type유입 경로 코드
kakao_extra상담하기 링크에 넣어 둔 값. 넣지 않았으면 키가 아예 없습니다

kakao_started_type 값은 다음과 같습니다.

값유입 경로
UM채팅방에서 바로 시작
BPPC 웹의 상담하기 버튼
BM모바일 웹의 상담하기 버튼
QRQR 코드
BA알림톡의 상담하기 버튼
SW챗봇에서 상담원 연결로 전환
{
"metadata": {
"kakao_started_type": "BP",
"kakao_extra": "promo_0923"
}
}

연동하실 때 알아 두실 점이 넷 있습니다.

  • 카카오 상담톡 대화에만 채워 드립니다. 다른 채널의 대화에는 저희가 이 두 키를 넣지 않습니다(운영하시면서 직접 넣어 두신 값이 있다면 그건 그대로 전달됩니다).
  • 카카오 대화라도 항상 오지는 않습니다. 해당 상담 세션을 찾지 못하면 두 키가 함께 빠집니다. 키가 없는 것을 "채팅방에서 바로 시작"으로 읽지 마세요.
  • 위 표에 없는 값이 올 수 있습니다. 카카오가 새 코드를 추가하면 그 값을 그대로 전달합니다. 모르는 값은 버리지 말고 그대로 두시는 편이 안전합니다.
  • 같은 대화의 첫 웹훅과 나중 웹훅의 값이 다를 수 있습니다. 버튼 유입 알림이 첫 메시지보다 늦게 도착하면, 처음에는 UM으로 왔다가 이후 웹훅부터 BP 같은 버튼 경로로 바뀝니다. 바뀌었다는 별도 웹훅은 보내지 않습니다.