대화형 답변 생성 API
안내
이 문서는 이전 버전인 v1 API에 대한 문서입니다.
신규 연동 시에는 기능과 응답 구조가 개선된 v2 API 사용을 권장합니다.
v2 API 문서: 대화형 답변 생성 API (V2)
기존 v1 API를 사용 중인 경우에도 안정적인 서비스 이용을 위해 v2로의 전환을 권장합니다.
목적
이 API는 사용자 메시지를 전달하고, AI의 응답을 반환합니다.
응답은 일반 JSON 또는 스트림(SSE, Server-Sent Events) 방식으로 받을 수 있습니다.
또한 응답에 포함되는 chat_log_uuid를 이용해, 해당 대화에 대해 도움이 됐어요 / 도움이 안 됐어요 피드백을 저장할 수 있습니다.
URL
HTTP 메서드
Shell
POST헤더
| 헤더 | 값 | 설명 |
| Content-Type | application/json | 요청 본문이 JSON 형식임을 나타냅니다. |
| Authorization | Bearer <api_key> | Sidetalk 대시보드에서 설치하기 메뉴에 제공된 API 키를 사용하세요. |
본문
| 파라미터 | 타입 | 필수 | 설명 |
| message | String | 예 | 사용자 메시지입니다. |
| stream | Boolean | 아니요 | 응답을 스트림으로 받을지 여부를 지정합니다. true 또는 false. 지정하지 않으면 기본값 false가 사용됩니다. |
| sessionId | String | 아니요 | 대화 세션을 구분하는 고유 키(Key)입니다. 이전 대화 내용을 기억하여 대화를 이어가려면 동일한 값을 유지해야 합니다. |
| memberId | String | 아니요 | 고객을 구분하는 회원 고유 ID입니다. 대화 로그를 특정 고객과 연결하려면 전달합니다. 동일한 고객의 대화를 추적하려면 항상 같은 값을 사용하세요. |
요청 예시
Shell
curl -X POST https://api.sidetalk.ai/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${API_KEY}" \
-d '{
"message": "안녕하세요, 도움이 필요해요.",
"stream": false,
"sessionId": "test-session-id",
"memberId": "user_123"
}'응답 형식
응답은
stream 값에 따라 두 가지 방식으로 제공됩니다.1-1. 스트림 응답 (stream: true)
응답은 SSE(Server-Sent Events) 형식으로 전달됩니다.
각 이벤트는
\n\n 으로 구분되며, event: 와 data: 필드를 포함할 수 있습니다.stream: true 인 경우 에이전트 실행 결과는 extra 필드로 반환되지 않고, 각 이벤트별로 개별 전달됩니다.주요 이벤트 종류
| 이벤트명 | 설명 |
|---|---|
message | 일반 텍스트 응답 조각입니다. |
showCard | 카드형 응답 데이터입니다. |
inputForm | 입력 폼 데이터입니다. |
reservationBookingForm | 예약 입력 폼 데이터입니다. |
reservationLookupForm | 예약 조회 폼 데이터입니다. |
pageRedirect | 페이지 이동용 링크 데이터입니다. |
message 이벤트 데이터 구조
| 필드 | 타입 | 설명 |
|---|---|---|
chunk | String | AI 응답의 일부 텍스트입니다. |
chat_log_uuid | String | 해당 대화 로그의 UUID입니다. 이후 피드백 저장 시 사용합니다. |
outsideData | String | 응답 외부에 표시할 추가 데이터입니다. 있을 때만 포함될 수 있습니다. |
기본 응답 예시 (message)
JSON
event: message
data: {"chunk":"안녕하세요, ","chat_log_uuid":"2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"}
event: message
data: {"chunk":"무엇을 도와드릴까요?","chat_log_uuid":"2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"}
data: [DONE]카드 응답 예시 (showCard)
JSON
event: showCard
data: {
"schema": "sidetalk.card.v1",
"cardType": "text",
"displayMode": "carousel",
"items": [
{
"type": "text",
"title": "최근 주문 내역",
"description": "주문번호 1234 / 결제완료",
"buttons": [
{
"label": "상세 보기",
"action": "user_utterance",
"value": "주문 상세 보여줘"
}
]
}
]
}입력 폼 응답 예시 (inputForm)
JSON
event: inputForm
data: {
"type": "showInputForm",
"task_id": "task_101",
"order": 1,
"question": "예약 신청할게요.",
"form_id": 101,
"form_name": "예약 신청",
"guide_message": "아래 정보를 입력해 주세요.",
"field_list": [
{
"field_id": "customer_name",
"field_label": "이름",
"field_type": "text",
"field_placeholder": "이름을 입력하세요",
"field_default_value": "",
"field_required_value": "1",
"order_index": 1,
"linked_column_id": "",
"field_options": ""
},
{
"field_id": "customer_phone",
"field_label": "연락처",
"field_type": "text",
"field_placeholder": "010-0000-0000",
"field_default_value": "",
"field_required_value": "1",
"order_index": 2,
"linked_column_id": "",
"field_options": ""
}
],
"executionHistory": [
{
"task_order": 1,
"action_type": "showInputForm",
"description": "입력폼 표시",
"data": null
}
],
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"
}입력폼 응답 후 처리
inputForm 응답이 반환되면 클라이언트는 입력 폼 UI를 표시해야 합니다.사용자가 입력을 완료하면, 응답에 포함된
form_id, task_id, order, executionHistory, chat_log_uuid 값과 사용자가 입력한 form_data 를 함께 구성하여 입력폼 제출 API로 전달합니다.자세한 요청 형식은
입력폼 제출 API 문서를 참고하세요.예약 입력 폼 응답 예시 (reservationBookingForm)
JSON
event: reservationBookingForm
data: {
"type": "reservationBookingForm",
"form_id": "reservation_booking_request",
"form_name": "예약 신청",
"guide_message": "예약에 필요한 정보를 입력해 주세요.",
"reservation_step": "customer_info",
"field_list": [
{
"field_id": "customer_name",
"field_label": "이름",
"field_type": "text",
"field_placeholder": "이름을 입력하세요",
"field_required_value": "1"
},
{
"field_id": "customer_phone",
"field_label": "연락처",
"field_type": "text",
"field_placeholder": "010-0000-0000",
"field_required_value": "1"
}
],
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"
}예약 조회 폼 응답 예시 (reservationLookupForm)
JSON
event: reservationLookupForm
data: {
"type": "reservationLookupForm",
"form_id": "reservation_lookup_request",
"form_name": "예약 조회",
"guide_message": "예약번호를 입력해 주세요.",
"field_list": [
{
"field_id": "reservation_no",
"field_label": "예약번호",
"field_type": "text",
"field_placeholder": "예약번호를 입력하세요",
"field_required_value": "1"
}
],
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"
}페이지 이동 응답 예시 (pageRedirect)
JSON
event: pageRedirect
data: {
"url": "https://example.com/reservation"
}스트림 처리 시 주의사항
- 각 메시지를
\n\n기준으로 분리합니다. event:값이 있는 경우 이벤트 종류를 함께 처리해야 합니다.data: [DONE]이 오면 스트림이 종료된 것입니다.message이벤트의chat_log_uuid는 피드백 API 호출 시 필요하므로 저장해 두는 것을 권장합니다.showCard,inputForm,reservationBookingForm,reservationLookupForm,pageRedirect이벤트는 일반 텍스트가 아니라 구조화된 에이전트 응답 데이터이므로 이벤트 이름에 따라 별도로 처리해야 합니다.
1-2. JSON 응답 (stream: false 또는 생략)
응답은 JSON 형식으로 반환됩니다.
stream: false 인 경우 일반 텍스트 응답은 message.content 로 반환되며,에이전트 실행 결과가 있는 경우
extra 필드에 함께 포함될 수 있습니다.기본 응답 본문
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "안녕하세요, 무엇을 도와드릴까요?"
}
}응답 필드 설명
| 필드 | 타입 | 설명 |
|---|---|---|
success | Boolean | 요청 성공 여부입니다. 성공 시 항상 true 입니다. |
chat_log_uuid | String | 해당 대화 로그의 UUID입니다. 피드백 저장 시 사용합니다. |
message | Object | AI의 응답 메시지 객체입니다. |
message.content | String | AI의 전체 응답 텍스트입니다. |
extra | Object | 에이전트 실행 결과가 있을 때만 포함될 수 있는 확장 필드입니다. |
에이전트 실행 결과가 포함된 JSON 응답
에이전트 실행 결과가 있는 경우
extra 필드에 구조화된 응답 데이터가 포함될 수 있습니다.실제 응답에서는 필요한
extra 필드만 포함됩니다.1) 카드 응답 예시 (extra.showCard)
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": ""
},
"extra": {
"showCard": {
"schema": "sidetalk.card.v1",
"cardType": "text",
"displayMode": "carousel",
"items": [
{
"type": "text",
"title": "최근 주문 내역",
"description": "주문번호 1234 / 결제완료",
"buttons": [
{
"label": "상세 보기",
"action": "user_utterance",
"value": "주문 상세 보여줘"
}
]
}
]
}
}
}2) 입력 폼 응답 예시 (extra.inputForm)
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "예약 입력이 필요합니다."
},
"extra": {
"inputForm": {
"type": "showInputForm",
"task_id": "task_101",
"order": 1,
"question": "예약 신청할게요.",
"form_id": 101,
"form_name": "예약 신청",
"guide_message": "아래 정보를 입력해 주세요.",
"field_list": [
{
"field_id": "customer_name",
"field_label": "이름",
"field_type": "text",
"field_placeholder": "이름을 입력하세요",
"field_default_value": "",
"field_required_value": "1",
"order_index": 1,
"linked_column_id": "",
"field_options": ""
},
{
"field_id": "customer_phone",
"field_label": "연락처",
"field_type": "text",
"field_placeholder": "010-0000-0000",
"field_default_value": "",
"field_required_value": "1",
"order_index": 2,
"linked_column_id": "",
"field_options": ""
}
],
"executionHistory": [
{
"task_order": 1,
"action_type": "showInputForm",
"description": "입력폼 표시",
"data": null
}
],
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"
}
}
}입력폼 응답 후 처리
inputForm 응답이 반환되면 클라이언트는 입력 폼 UI를 표시해야 합니다.사용자가 입력을 완료하면, 응답에 포함된
form_id, task_id, order, executionHistory, chat_log_uuid 값과 사용자가 입력한 form_data 를 함께 구성하여 입력폼 제출 API로 전달합니다.자세한 요청 형식은
입력폼 제출 API 문서를 참고하세요.3) 예약 입력 폼 응답 예시 (extra.reservationBookingForm)
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "예약 입력이 필요합니다."
},
"extra": {
"reservationBookingForm": {
"type": "reservationBookingForm",
"form_id": "reservation_booking_request",
"form_name": "예약 신청",
"guide_message": "예약에 필요한 정보를 입력해 주세요.",
"reservation_step": "customer_info",
"field_list": [
{
"field_id": "customer_name",
"field_label": "이름",
"field_type": "text",
"field_placeholder": "이름을 입력하세요",
"field_required_value": "1"
},
{
"field_id": "customer_phone",
"field_label": "연락처",
"field_type": "text",
"field_placeholder": "010-0000-0000",
"field_required_value": "1"
}
]
}
}
}4) 예약 조회 폼 응답 예시 (extra.reservationLookupForm)
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "예약 조회가 필요합니다."
},
"extra": {
"reservationLookupForm": {
"type": "reservationLookupForm",
"form_id": "reservation_lookup_request",
"form_name": "예약 조회",
"guide_message": "예약번호를 입력해 주세요.",
"field_list": [
{
"field_id": "reservation_no",
"field_label": "예약번호",
"field_type": "text",
"field_placeholder": "예약번호를 입력하세요",
"field_required_value": "1"
}
]
}
}
}5) 페이지 이동 응답 예시 (extra.pageRedirect)
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "예약 페이지로 이동합니다."
},
"extra": {
"pageRedirect": {
"url": "https://example.com/reservation"
}
}
}extra 필드 설명
| 필드 | 타입 | 설명 |
|---|---|---|
extra.showCard | Object | 카드형 응답 데이터입니다. 채팅창에서는 카드 UI로 표시됩니다. |
extra.inputForm | Object | 입력 폼 데이터입니다. 채팅창에서는 입력 폼 UI로 표시됩니다. |
extra.reservationBookingForm | Object | 예약 입력 폼 데이터입니다. 채팅창에서는 예약 입력 폼 UI로 표시됩니다. |
extra.reservationLookupForm | Object | 예약 조회 폼 데이터입니다. 채팅창에서는 예약 조회 폼 UI로 표시됩니다. |
extra.pageRedirect | Object | 페이지 이동 데이터입니다. 클라이언트에서 링크 이동 처리에 사용합니다. |
클라이언트 구현 권장 순서
extra.showCard가 있으면 카드 UI를 표시합니다.extra.inputForm이 있으면 입력 폼 UI를 표시합니다.extra.reservationBookingForm이 있으면 예약 입력 폼 UI를 표시합니다.extra.reservationLookupForm이 있으면 예약 조회 폼 UI를 표시합니다.extra.pageRedirect가 있으면 이동 버튼 또는 자동 이동을 처리합니다.- 위 값이 없으면
message.content를 일반 텍스트 답변으로 표시합니다.
2. 대화 피드백 API
대화 응답에서 받은
chat_log_uuid를 이용해, 해당 대화에 대한 피드백을 저장할 수 있습니다.URL
Plain Text
https://api.sidetalk.ai/v1/chat/feedbackHTTP 메서드
Plain Text
POST헤더
| 헤더 | 값 | 설명 |
|---|---|---|
| Content-Type | application/json | 요청 본문이 JSON 형식임을 나타냅니다. |
| Authorization | Bearer <api_key> | Sidetalk 대시보드에서 제공된 API 키를 사용합니다. |
본문
| 파라미터 | 타입 | 필수 | 설명 |
|---|---|---|---|
| session_id | String | 예 | 피드백을 저장할 대화의 세션 ID입니다. 대화 요청 시 사용한 sessionId와 동일한 값이어야 합니다. |
| chat_log_uuid | String | 예 | chat/completions 응답에서 받은 대화 UUID입니다. |
| chat_log_feedback | String | 예 | 피드백 값입니다. 1은 도움이 됨, 2는 도움이 안 됨을 의미합니다. |
요청 예시
Shell
curl -X POST https://api.sidetalk.ai/v1/chat/feedback \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${API_KEY}" \
-d '{
"session_id": "test-session-id",
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"chat_log_feedback": "1"
}'성공 응답 예시
JSON
{
"success": true,
"updated": true,
"already_saved": false,
"feedback": "1"
}응답 필드 설명
| 필드 | 타입 | 설명 |
|---|---|---|
| success | Boolean | 요청 성공 여부입니다. |
| updated | Boolean | 이번 요청으로 실제 저장이 이루어졌는지 여부입니다. |
| already_saved | Boolean | 이미 피드백이 저장되어 있었는지 여부입니다. |
| feedback | String | 최종 저장된 피드백 값입니다. |
3. 피드백 저장 조건 및 주의사항
- 피드백 저장 시
session_id는 대화 요청 시 사용한sessionId와 동일해야 합니다. chat_log_uuid는 반드시 해당 응답에서 받은 값이어야 합니다.- 피드백은 완료된 대화에만 저장할 수 있습니다.
- 이미 저장된 피드백은 다시 변경되지 않을 수 있습니다. 이 경우
already_saved: true가 반환될 수 있습니다. chat_log_feedback는 반드시 문자열 "1" 또는 "2"여야 합니다.- 권장 방식은:
- chat/completions 호출
- 응답에서 chat_log_uuid 저장
- 사용자가 버튼 클릭
- chat/feedback 호출
예시 코드 (JavaScript)
스트림 응답 처리 (stream이 true인 경우)
JavaScript
function sendMessage(message) {
const apiUrl = "https://api.sidetalk.ai/v1/chat/completions";
const requestData = {
"message": message,
"stream": true // 없는 경우 기본값 false로 설정됩니다.
};
fetch(apiUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer [API_KEY]"
},
body: JSON.stringify(requestData),
})
.then(async response => {
// HTTP 상태 코드 확인
if (!response.ok) {
const errorData = await response.json();
console.error("Server Error:", errorData.message || 'Unknown error');
return;
}
if (!response.body) throw new Error("ReadableStream not supported in response.");
const reader = response.body.getReader();
const decoder = new TextDecoder();
function readStream() {
return reader.read().then(({ done, value }) => {
if (done) {
console.log("Stream complete.");
return;
}
const chunk = decoder.decode(value, { stream: true });
const messages = chunk.split("\n\n");
messages.forEach(message => {
if (message.startsWith("data: ")) {
const dataStr = message.replace("data: ", "");
if (dataStr === "[DONE]") {
console.log("Stream finished with [DONE] signal.");
reader.cancel();
return;
}
try {
const data = JSON.parse(dataStr);
// 서버에서 success: false를 보내는 경우 오류 처리
if (data.success === false) {
console.error("Error from server:", data.message || 'Unknown error');
reader.cancel();
return;
}
if (data.chunk) {
console.log("Chunk received:", data.chunk);
// 응답 처리 로직 추가
}
if (data.outsideData) {
console.log("Outside data received:", data.outsideData);
// 추가 데이터 처리 로직 추가
}
} catch (error) {
console.error("Error parsing JSON:", error);
}
}
});
return readStream();
});
}
return readStream();
})
.catch(error => {
console.error("Error receiving stream:", error);
});
}4. JavaScript 예시
4-1. JSON 응답 처리 예시
JavaScript
async function sendMessage(message) {
const response = await fetch("https://api.sidetalk.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer [API_KEY]"
},
body: JSON.stringify({
message,
stream: false,
sessionId: "test-session-id",
memberId: "user_123"
})
});
const data = await response.json();
if (!response.ok || !data.success) {
console.error("Server Error:", data.message || data.error || "Unknown error");
return;
}
console.log("AI 답변:", data.message.content);
console.log("chat_log_uuid:", data.chat_log_uuid);
return {
answer: data.message.content,
chatLogUuid: data.chat_log_uuid
};
}4-2. 스트림 응답 처리 예시
JavaScript
async function sendMessageStream(message) {
const response = await fetch("https://api.sidetalk.ai/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer [API_KEY]"
},
body: JSON.stringify({
message,
stream: true,
sessionId: "test-session-id"
})
});
if (!response.ok) {
const errorData = await response.json();
console.error("Server Error:", errorData.message || errorData.error || "Unknown error");
return;
}
if (!response.body) {
throw new Error("ReadableStream not supported in response.");
}
const reader = response.body.getReader();
const decoder = new TextDecoder();
let savedChatLogUuid = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunkText = decoder.decode(value, { stream: true });
const blocks = chunkText.split("\n\n");
for (const block of blocks) {
if (!block.trim()) continue;
const lines = block.split("\n");
let eventName = "message";
const dataLines = [];
for (const line of lines) {
if (line.startsWith("event:")) {
eventName = line.replace("event:", "").trim();
}
if (line.startsWith("data:")) {
dataLines.push(line.replace("data:", "").trimStart());
}
}
const dataStr = dataLines.join("\n").trim();
if (!dataStr) continue;
if (dataStr === "[DONE]") {
console.log("Stream finished.");
return savedChatLogUuid;
}
try {
const data = JSON.parse(dataStr);
if (eventName === "message" && data.chunk) {
console.log("Chunk:", data.chunk);
}
if (data.chat_log_uuid && !savedChatLogUuid) {
savedChatLogUuid = data.chat_log_uuid;
console.log("chat_log_uuid:", savedChatLogUuid);
}
if (eventName === "showCard") {
console.log("Show card payload:", data);
}
if (eventName === "inputForm") {
console.log("Input form payload:", data);
}
if (eventName === "pageRedirect") {
console.log("Redirect payload:", data);
}
} catch (error) {
console.error("Error parsing stream JSON:", error);
}
}
}
return savedChatLogUuid;
}4-3. 피드백 저장 예시
JavaScript
async function sendFeedback({ sessionId, chatLogUuid, isHelpful }) {
const feedbackValue = isHelpful ? "1" : "2";
const response = await fetch("https://api.sidetalk.ai/v1/chat/feedback", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer [API_KEY]"
},
body: JSON.stringify({
session_id: sessionId,
chat_log_uuid: chatLogUuid,
chat_log_feedback: feedbackValue
})
});
const data = await response.json();
if (!response.ok || !data.success) {
console.error("Feedback Error:", data.error || data.message || "Unknown error");
return null;
}
console.log("Feedback saved:", data);
return data;
}5. 오류 응답
오류가 발생한 경우 다음과 같은 형식으로 응답이 반환될 수 있습니다.
응답 예시
JavaScript
{
"success": false,
"message": "서버 오류가 발생했습니다.",
"error": "오류 메시지 내용"
}또는 피드백 API에서는 아래와 같은 형식이 반환될 수 있습니다.
JavaScript
{
"success": false,
"error": "chat_log_feedback must be 1 or 2"
}주요 오류 케이스
| HTTP 상태 | 예시 | 설명 |
|---|---|---|
| 400 | chat_log_feedback must be 1 or 2 | 피드백 값이 잘못된 경우 |
| 400 | session_id, chat_log_uuid, chat_log_feedback are required | 필수 파라미터가 누락된 경우 |
| 403 | Authentication error | API 인증에 실패한 경우 |
| 404 | not_found | 해당 대화 로그를 찾을 수 없는 경우 |
| 500 | 서버 오류 | 서버 내부 오류가 발생한 경우 |
6. 참고 사항
stream을 지정하지 않으면 기본값은false이며, JSON 응답으로 반환됩니다.- 피드백 저장을 위해서는 반드시
chat_log_uuid를 클라이언트에서 저장해야 합니다. chat/completions요청 시의sessionId와chat/feedback요청 시의session_id는 같은 값을 사용해야 합니다.- 스트림 응답은
message외에도 다양한event:를 포함할 수 있으므로, 단순히data:만 파싱하지 말고event:도 함께 처리하는 것을 권장합니다. - 피드백 API는
good,bad를 별도 엔드포인트로 나누지 않고 하나의 API에서chat_log_feedback값으로 구분합니다.
