서버
서버 API
서버 API로 대화 목록을 가져오고, 답장하고, 상태를 바꾸고, 대화를 이슈로 만들 수 있어요. 자체 관리자 화면에 상담 기능을 붙일 때 쓰세요.
인증
모든 요청에 Authorization: Bearer ent_sk_…를 붙여요. 시크릿 키는 서버끼리만 쓰고, 브라우저나 앱에 넣지 마세요. 키는 발급된 채널에만 쓸 수 있어요. 다른 채널의 channelId로는 어떤 데이터도 읽거나 바꿀 수 없어요.
우리 서비스의 상담원이 답하는 경우, 누가 답했는지 X-Entropy-Operator 헤더로 알려 주세요. 값은 { id, name, avatarUrl } JSON을 base64url로 인코딩한 문자열이에요. 엔트로피 안에서 답하는 운영자는 엔트로피 로그인 세션을 쓰고, 메신저 권한이 있는 조직 멤버여야 해요.
const operator = { id: 'op_7', name: '상담원', avatarUrl: 'https://example.com/a/7.png' };
const header = Buffer.from(JSON.stringify(operator)).toString('base64url');엔드포인트
| 요청 | 설명 |
|---|---|
GET /v1/channels/:channelId/conversations | 대화 목록. state, assignee, kind, q, cursor로 걸러요. |
GET /v1/channels/:channelId/conversations/:id | 대화 한 건과 연락처 정보 |
GET /v1/channels/:channelId/conversations/:id/messages | 메시지 목록(운영자 메모 포함) |
POST /v1/channels/:channelId/conversations/:id/messages | { body, attachmentIds?, internal? }로 답장하거나 메모를 남겨요. |
PATCH /v1/channels/:channelId/conversations/:id | { state?, assignee?, tags?, kind? } — 종료, 보류, 담당자 지정 |
POST /v1/channels/:channelId/conversations/:id/read | 운영자 쪽 읽음 처리 |
GET /v1/channels/:channelId/contacts/:id | 연락처 조회 |
PATCH /v1/channels/:channelId/contacts/:id | { externalMemberId? } — 우리 회원과 잇기 |
POST /v1/channels/:channelId/conversations/:id/issue | { title?, projectId? } — 엔트로피 이슈를 만들고 대화와 이어요. |
GET /v1/channels/:channelId/stream | 운영자용 실시간 이벤트(SSE) |
GET /v1/channels/:channelId/stats | 채널 통계 |
POST /v1/channels/:channelId/contacts/erase | { externalMemberId } — 탈퇴한 회원의 연락처와 상담 기록을 모두 지워요. |
예제
# 열린 대화 목록
curl https://entropy.ly/api/v1/channels/$CHANNEL_ID/conversations?state=open \
-H "Authorization: Bearer $ENTROPY_SECRET_KEY" \
-H "X-Entropy-Operator: $(printf '{"id":"op_7","name":"상담원"}' | base64 | tr '+/' '-_' | tr -d '=')"
# 답장 보내기 (internal: true면 고객에게 보이지 않는 메모)
curl -X POST https://entropy.ly/api/v1/channels/$CHANNEL_ID/conversations/$CONVERSATION_ID/messages \
-H "Authorization: Bearer $ENTROPY_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"body":"확인해 보고 바로 알려 드릴게요."}'대화 목록 응답
{
"items": [
{
"id": "cv_01J8Z3K6W2",
"channelId": "ch_01J…",
"contactId": "ct_01J…",
"kind": "support",
"state": "open",
"assignee": {
"type": "external",
"id": "op_7",
"name": "상담원",
"avatarUrl": null
},
"tags": [
"결제"
],
"lastMessage": "영수증을 다시 받을 수 있을까요?",
"lastMessageAt": "2026-10-27T08:59:40Z",
"unreadForContact": 0,
"unreadForOperator": 1,
"linkedIssueId": null,
"createdAt": "2026-10-27T08:58:02Z"
}
],
"nextCursor": "eyJ0IjoiMjAyNi0xMC0yN1QwODo1ODowMloifQ"
}페이지 나누기
목록 응답은 { items, nextCursor } 형태예요. 다음 페이지는 nextCursor를 cursor로 넘겨서 받아요. nextCursor가 null이면 마지막 페이지예요. 커서는 그대로 전달만 하고 해석하지 마세요.
대화를 이슈로 만들기
POST /v1/channels/:channelId/conversations/cv_01J8Z3K6W2/issue
Content-Type: application/json
{
"title": "영수증 재발급 버튼 추가",
"projectId": "prj_01J…"
}이슈가 만들어지면 대화의 linkedIssueId가 채워져요. 이슈 상태가 바뀌면 웹훅 feedback.status_changed가 가고, 고객에게 반영 소식을 전할 수 있어요.
탈퇴 회원 삭제
회원이 탈퇴하거나 계정을 지우면 서버에서 바로 호출하세요. 그 회원과 이어진 연락처의 이름·이메일·휴대폰·동의 기록, 모든 대화와 메시지, 첨부 파일을 지우고 익명 집계 숫자만 남겨요. 시크릿 키로만 부를 수 있고, 다른 채널의 연락처는 지울 수 없어요.
POST /v1/channels/:channelId/contacts/erase
Content-Type: application/json
{
"externalMemberId": "user_2041"
}{
"status": "erased",
"contactId": "ct_01J…",
"erasedAt": "2026-11-04T05:00:00Z",
"counts": {
"conversations": 2,
"messages": 17,
"attachments": 1
}
}erased(200) — 지금 지웠어요.not_found(200) — 남은 기록이 없어요. 여러 번 불러도 결과가 같으니 재시도해도 안전해요.pending(202) — 접근은 바로 막았고 삭제는 백그라운드에서 마저 끝내요.held(202) — 법적 보존 요청으로 보관 중이라 해제되면 지워요. 둘 다 다시 부를 필요 없어요.dry_run(202,dryRun: true) — 엔트로피가 시험 모드라서 아무것도 지우지 않고 지울 대상만 기록했어요. 이것도 다시 부를 필요 없어요.5xx·429·네트워크 오류일 때만 간격을 두고 다시 시도하세요. 이 호출 때문에 탈퇴 처리를 막지는 마세요.- 지운 뒤에는 웹훅
contact.erased가 가요. 대화는 채널의 보관 기간(기본 3년)이 지나도 자동으로 지워져요.
실시간 이벤트
GET /v1/channels/:channelId/stream은 Server-Sent Events로 채널의 message.created, conversation.updated, typing, read를 보내요. 25초마다 하트비트가 와요. 연결이 끊기면 다시 연결하고, 그동안 놓친 변경은 목록 API로 다시 가져오세요.