Conversational Answer Generation API
Notice
This document covers the previous v1 API.
For new integrations, use the v2 API with improved features and response structure.
v2 API documentation: Conversational Answer Generation API (V2)
Existing v1 users are also encouraged to migrate to v2 for stable service.
Purpose
This API forwards user messages and returns AI responses.
Responses are available as regular JSON or a stream (SSE, Server-Sent Events).
Use the chat_log_uuid included in the response to save Helpful / Not Helpful feedback for the conversation.
URL
HTTP method
Shell
POSTHeaders
| Headers | Value | Description |
| Content-Type | application/json | Indicates that the request body is JSON. |
| Authorization | Bearer <api_key> | Use the API key provided in Install in the Sidetalk dashboard. |
Body
| Parameter | Type | Required | Description |
| message | String | Yes | The user’s message. |
| stream | Boolean | No | Whether to receive a streamed response: true or false. Defaults to false if omitted. |
| sessionId | String | No | A unique key identifying the conversation session. Keep the same value to remember previous messages and continue the conversation. |
| memberId | String | No | A unique member ID identifying the customer. Pass it to associate conversation logs with a customer. Always use the same value to track the same customer’s conversations. |
Example request
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"
}'Response format
Responses are provided in two ways depending on stream.
1-1. Streamed response (stream: true)
Responses are delivered in SSE (Server-Sent Events) format.
Events are separated by \n\n and may include event: and data: fields.
With stream: true, agent execution results are delivered as individual events rather than in an extra field.
Main event types
| Event name | Description |
|---|---|
message | A fragment of a regular text response. |
showCard | Card response data. |
inputForm | Form data. |
reservationBookingForm | Reservation booking form data. |
reservationLookupForm | Reservation lookup form data. |
pageRedirect | Link data for page navigation. |
message event data structure
| Field | Type | Description |
|---|---|---|
chunk | String | Part of the AI response text. |
chat_log_uuid | String | The UUID of the conversation log. Used later to save feedback. |
outsideData | String | Additional data to display outside the response. May be included only when available. |
Basic response example (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]Card response example (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": "주문 상세 보여줘"
}
]
}
]
}Form response example (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"
}Handling a form response
When inputForm is returned, the client must display the form UI.
After the user completes input, combine form_id, task_id, order, executionHistory, and chat_log_uuid from the response with the submitted form_data and send them to the Form Submission API.
See the Form Submission API documentation for the detailed request format.
Reservation booking form response example (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"
}Reservation lookup form response example (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"
}Page navigation response example (pageRedirect)
JSON
event: pageRedirect
data: {
"url": "https://example.com/reservation"
}Stream handling notes
- Separate messages by \n\n.
- If event: is present, handle the event type as well.
- data: [DONE] indicates the end of the stream.
- Save chat_log_uuid from message events because it is needed when calling the feedback API.
- showCard, inputForm, reservationBookingForm, reservationLookupForm, and pageRedirect events contain structured agent response data rather than ordinary text. Handle each separately according to its event name.
1-2. JSON response (stream: false or omitted)
The response is returned as JSON.
With stream: false, the regular text response is returned in message.content,
and agent execution results may be included in extra.
Basic response body
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "안녕하세요, 무엇을 도와드릴까요?"
}
}Response fields
| Field | Type | Description |
|---|---|---|
success | Boolean | Whether the request succeeded. Always true on success. |
chat_log_uuid | String | The conversation log UUID, used to save feedback. |
message | Object | The AI response message object. |
message.content | String | The full AI response text. |
extra | Object | An extension field that may be included only when agent execution results exist. |
JSON response with agent execution results
When agent execution results are available, extra may contain structured response data.
Only the necessary extra fields are included in an actual response.
1) Card response example (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) Form response example (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"
}
}
}Handling a form response
When inputForm is returned, the client must display the form UI.
After the user completes input, combine form_id, task_id, order, executionHistory, and chat_log_uuid from the response with the submitted form_data and send them to the Form Submission API.
See the Form Submission API documentation for the detailed request format.
3) Reservation booking form response example (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) Reservation lookup form response example (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) Page navigation response example (extra.pageRedirect)
JSON
{
"success": true,
"chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
"message": {
"content": "예약 페이지로 이동합니다."
},
"extra": {
"pageRedirect": {
"url": "https://example.com/reservation"
}
}
}extra fields
| Field | Type | Description |
|---|---|---|
extra.showCard | Object | Card response data, displayed as card UI in chat. |
extra.inputForm | Object | Form data, displayed as form UI in chat. |
extra.reservationBookingForm | Object | Reservation booking form data, displayed as booking form UI in chat. |
extra.reservationLookupForm | Object | Reservation lookup form data, displayed as lookup form UI in chat. |
extra.pageRedirect | Object | Page navigation data, used by the client to navigate links. |
Recommended client implementation order
- If extra.showCard exists, display the card UI.
- If extra.inputForm exists, display the form UI.
- If extra.reservationBookingForm exists, display the reservation booking form UI.
- If extra.reservationLookupForm exists, display the reservation lookup form UI.
- If extra.pageRedirect exists, handle a navigation button or automatic redirect.
- If none of those values exist, display message.content as the regular text answer.
2. Conversation Feedback API
Use chat_log_uuid from the conversation response to save feedback for that conversation.
URL
Plain Text
https://api.sidetalk.ai/v1/chat/feedbackHTTP method
Plain Text
POSTHeaders
| Headers | Value | Description |
|---|---|---|
| Content-Type | application/json | Indicates that the request body is JSON. |
| Authorization | Bearer <api_key> | Use the API key provided in the Sidetalk dashboard. |
Body
| Parameter | Type | Required | Description |
|---|---|---|---|
| session_id | String | Yes | The session ID of the conversation whose feedback is being saved. Must match sessionId from the conversation request. |
| chat_log_uuid | String | Yes | The conversation UUID received from the chat/completions response. |
| chat_log_feedback | String | Yes | Feedback value: 1 means helpful; 2 means not helpful. |
Example request
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"
}'Example success response
JSON
{
"success": true,
"updated": true,
"already_saved": false,
"feedback": "1"
}Response fields
| Field | Type | Description |
|---|---|---|
| success | Boolean | Whether the request succeeded. |
| updated | Boolean | Whether this request actually saved feedback. |
| already_saved | Boolean | Whether feedback was already saved. |
| feedback | String | The final saved feedback value. |
3. Feedback storage requirements and notes
- When saving feedback, session_id must match the sessionId used for the conversation request.
- chat_log_uuid must be the value received in that response.
- Feedback can be saved only for completed conversations.
- Saved feedback may not be changed again. In that case, already_saved: true may be returned.
- chat_log_feedback must be the string "1" or "2".
- Recommended approach:
- Call chat/completions
- Save chat_log_uuid from the response
- The user clicks a button
- Call chat/feedback
Example code (JavaScript)
Handle streamed responses (when stream is 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 example
4-1. JSON response handling example
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. Streamed response handling example
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. Feedback storage example
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. Error responses
When an error occurs, a response may be returned in the following format.
Example response
JavaScript
{
"success": false,
"message": "서버 오류가 발생했습니다.",
"error": "오류 메시지 내용"
}Alternatively, the feedback API may return the following format.
JavaScript
{
"success": false,
"error": "chat_log_feedback must be 1 or 2"
}Main error cases
| HTTP status | Example | Description |
|---|---|---|
| 400 | chat_log_feedback must be 1 or 2 | Invalid feedback value |
| 400 | session_id, chat_log_uuid, chat_log_feedback are required | Missing required parameter |
| 403 | Authentication error | API authentication failure |
| 404 | not_found | Conversation log not found |
| 500 | Server error | An internal server error occurred |
6. Notes
- If stream is omitted, it defaults to false and returns a JSON response.
- The client must save chat_log_uuid to store feedback.
- Use the same value for sessionId in chat/completions and session_id in chat/feedback.
- Streams may contain various event: types in addition to message. Handle event: as well as parsing data:.
- The feedback API uses one endpoint and distinguishes good and bad feedback with chat_log_feedback, rather than separate endpoints.
