SidetalkGuides
Sidetalk website ↗Open dashboard

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.
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
POST

Headers

HeadersValueDescription
Content-Typeapplication/jsonIndicates that the request body is JSON.
AuthorizationBearer <api_key>Use the API key provided in Install in the Sidetalk dashboard.

Body

ParameterTypeRequiredDescription
messageStringYesThe user’s message.
streamBooleanNoWhether to receive a streamed response: true or false. Defaults to false if omitted.
sessionIdStringNoA unique key identifying the conversation session. Keep the same value to remember previous messages and continue the conversation.
memberIdStringNoA 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 nameDescription
messageA fragment of a regular text response.
showCardCard response data.
inputFormForm data.
reservationBookingFormReservation booking form data.
reservationLookupFormReservation lookup form data.
pageRedirectLink data for page navigation.

message event data structure

FieldTypeDescription
chunkStringPart of the AI response text.
chat_log_uuidStringThe UUID of the conversation log. Used later to save feedback.
outsideDataStringAdditional 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

FieldTypeDescription
successBooleanWhether the request succeeded. Always true on success.
chat_log_uuidStringThe conversation log UUID, used to save feedback.
messageObjectThe AI response message object.
message.contentStringThe full AI response text.
extraObjectAn 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

FieldTypeDescription
extra.showCardObjectCard response data, displayed as card UI in chat.
extra.inputFormObjectForm data, displayed as form UI in chat.
extra.reservationBookingFormObjectReservation booking form data, displayed as booking form UI in chat.
extra.reservationLookupFormObjectReservation lookup form data, displayed as lookup form UI in chat.
extra.pageRedirectObjectPage navigation data, used by the client to navigate links.

Recommended client implementation order

  1. If extra.showCard exists, display the card UI.
  2. If extra.inputForm exists, display the form UI.
  3. If extra.reservationBookingForm exists, display the reservation booking form UI.
  4. If extra.reservationLookupForm exists, display the reservation lookup form UI.
  5. If extra.pageRedirect exists, handle a navigation button or automatic redirect.
  6. 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/feedback

HTTP method

Plain Text
POST

Headers

HeadersValueDescription
Content-Typeapplication/jsonIndicates that the request body is JSON.
AuthorizationBearer <api_key>Use the API key provided in the Sidetalk dashboard.

Body

ParameterTypeRequiredDescription
session_idStringYesThe session ID of the conversation whose feedback is being saved. Must match sessionId from the conversation request.
chat_log_uuidStringYesThe conversation UUID received from the chat/completions response.
chat_log_feedbackStringYesFeedback 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

FieldTypeDescription
successBooleanWhether the request succeeded.
updatedBooleanWhether this request actually saved feedback.
already_savedBooleanWhether feedback was already saved.
feedbackStringThe 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:
    1. Call chat/completions
    2. Save chat_log_uuid from the response
    3. The user clicks a button
    4. 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 statusExampleDescription
400chat_log_feedback must be 1 or 2Invalid feedback value
400session_id, chat_log_uuid, chat_log_feedback are requiredMissing required parameter
403Authentication errorAPI authentication failure
404not_foundConversation log not found
500Server errorAn 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.