본문으로 건너뛰기

이벤트

ZeroTalk Outbound Webhook은 9개 이벤트를 전송합니다. 등록 시 일부만 구독하도록 필터링할 수 있으며, 필터를 비우면 전체를 구독합니다. (PAT API로 등록할 때는 event_filters로 지정합니다.)

노트

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

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

이벤트 목록

메시지

이벤트설명
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_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.createddata에는 위 예시 외에 attachments·metadata·seq_id·version도 있고(message.updated·message.deletedversion만), 채널 이벤트는 모두 version(채널 집계 버전)을 싣습니다.

발생 시각 필드는 일부 이벤트에만 있습니다 — created_atmessage.created·channel.created, deleted_atmessage.deleted, closed_atchannel.closed에만 있고, 나머지(message.updated·channel.reopened·channel.assigned·channel.snooze_expired)는 data에 발생 시각이 없습니다(channel.snoozedsnoozed_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는 data가 아니라 channel.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_typeintegration입니다. 상담원 쪽 UI에서는 member와 동일하게 상담원 측 메시지로 렌더링하고, 표시 이름은 토큰 이름을 사용하세요.

노트

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

이벤트별 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_typeblocks이면 구조화 본문이 blocks 키로 추가됩니다

message.updated

메시지 내용이 수정됨. changes에 바뀐 필드가 담깁니다.

{
"message_id": "msg_def456",
"sender_id": "mbr_111",
"sender_type": "member",
"content_type": "text",
"content": "수정된 전체 본문입니다.",
"is_last_message": true,
"changes": { "content": "수정된 전체 본문입니다." }
}

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, 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, 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