SidetalkGuides
Sidetalk website ↗Open dashboard

Conversational Answer Generation API (V2)

Related documentation


Purpose

This API forwards user messages and returns AI responses.
The v2 API can issue a new session on the server if session_id is absent.
Requests with the same session_id can continue the previous conversation.
Use chat_log_uuid included in the response to save Helpful / Not Helpful feedback for that conversation.

1. Chat Response Generation API

URL


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
messagesArrayYesThe message array. Only the last role: "user" message is used as the actual question.
streamBooleanNoWhether to receive a streamed response. Defaults to false.
session_idStringNoThe conversation session ID. The server issues one if absent.
sessionIdStringNoAn alias for session_id.
recommendedQuestionsBooleanNoIf true, includes suggested questions in the response. Defaults to false.

How messages is used

messages is sent as an array, but the server does not accept the entire conversation history from the request body.
Only the last role: "user" message in the messages array is used as the actual question.
Conversation history is not sent in messages each time. The server uses history stored under session_id.
For example, only the last user message in the request below is used as the actual question.
JSON
{
  "messages": [
    {
      "role": "user",
      "content": "첫 질문"
    },
    {
      "role": "assistant",
      "content": "이전 답변"
    },
    {
      "role": "user",
      "content": "마지막 질문"
    }
  ]
}
Value used as the actual question:
JSON
{
  "role": "user",
  "content": "마지막 질문"
}

session_id policy

In v2, the server can issue session_id.
SituationBehavior
No session_idThe server creates a new session_id and includes it in the response.
session_id provided and validContinues using the conversation history for that session.
session_id provided with an invalid formatReturns an error.
session_id provided but does not existReturns an error.
The recommended approach is:
  1. Make the first request without session_id.
  2. Save session_id from the response.
  3. Pass the same session_id in subsequent conversation requests.

recommendedQuestions policy

recommendedQuestions is optional.
Request conditionResponse behavior
Omitted or falseDoes not return suggested questions.
true with suggestions availableIncludes suggested questions in the response.
true with no suggestions availableReturns recommended_questions: [].
The server automatically looks up suggested questions based on the last role: "user" message.
With stream: false, they are returned in the top-level recommended_questions array.
With stream: true, look for a chunk whose sidetalk_event.type is recommendedQuestions and get the suggestions from sidetalk_event.data.items.
Suggested question identifiers are returned as knowledgeId.

Example request

Start a new conversation

JSON
curl -X POST https://api.sidetalk.ai/v2/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${API_KEY}" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "안녕하세요, 도움이 필요해요."
      }
    ],
    "stream": false
  }'

Continue an existing session

JSON
curl -X POST https://api.sidetalk.ai/v2/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${API_KEY}" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "이전 대화 내용 기준으로 다시 설명해줘."
      }
    ],
    "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
    "stream": false
  }'

Include suggested questions

JSON
curl -X POST https://api.sidetalk.ai/v2/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${API_KEY}" \
  -d '{
    "messages": [
      {
        "role": "user",
        "content": "사이드톡이 뭐야?"
      }
    ],
    "stream": false,
    "recommendedQuestions": true
  }'

Response format

Responses are provided in two ways depending on stream.

1-1. JSON response (stream: false or omitted)


Basic response example

JSON
{
  "success": true,
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion",
  "created": 1783928563,
  "model": "sidetalk",
  "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
  "chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "안녕하세요, 무엇을 도와드릴까요?"
      },
      "finish_reason": "stop"
    }
  ]
}

Response fields

FieldTypeDescription
successBooleanWhether the request succeeded.
idStringThe response ID, including the chatcmpl- prefix and chat_log_uuid.
objectStringThe response object type. Returns chat.completion.
createdNumberThe response creation time in Unix timestamp format.
modelStringThe response model name. Defaults to sidetalk.
session_idStringThe conversation session ID, used for subsequent requests.
chat_log_uuidStringThe conversation log UUID, used to save feedback.
choicesArrayThe list of response choices.
choices[0].indexNumberThe index of the response choice.
choices[0].message.roleStringThe response role, usually assistant.
choices[0].message.contentStringThe full AI response text.
choices[0].finish_reasonStringThe reason the response ended. Returns stop on normal completion.
recommended_questionsArraySuggested questions returned only with recommendedQuestions: true. Returns up to three items or an empty array if none are found. |

Suggested questions response example

JSON
{
  "success": true,
  "id": "chatcmpl-example",
  "object": "chat.completion",
  "created": 1787101993,
  "model": "sidetalk",
  "session_id": "4b025ddd-6a58-451a-9c29-6f221aa7bc9",
  "chat_log_uuid": "a5c88ab2-c7cf-412f-b080-dc6ba74ebeee",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "사이드톡은 질문에 답변하는 AI 서비스입니다."
      },
      "finish_reason": "stop"
    }
  ],
  "recommended_questions": [
    {
      "knowledgeId": "3356",
      "question": "추천 질문1",
      "type": "chat_data"
    },
    {
      "knowledgeId": "3357",
      "question": "추천 질문2",
      "type": "chat_data"
    },
    {
		  "knowledgeId": "3358",
		  "question": "추천 질문3",
		  "type": "chat_data"
		}
  ]
}

Suggested question item fields

FieldTypeDescription
recommended_questions[].knowledgeIdStringThe ID identifying a suggested question.
recommended_questions[].questionStringThe suggested question text shown to users.
recommended_questions[].typeStringThe source type of the suggested question. Examples: chat_data, notion, file, file_pdf

1-2. Streamed response (stream: true)

Responses are delivered in SSE (Server-Sent Events) format.
The stream first returns one metadata event, then returns answer fragments in order.

Main event types

Event nameDescription
metadataMetadata containing the session ID and conversation log UUID.
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.

metadata event data structure

FieldTypeDescription
session_idStringThe current conversation session ID.
chat_log_uuidStringThe current conversation log UUID.

metadata event example

JSON
event: metadata
data: {"session_id":"943f15db-3984-4f21-ad64-f0115839c3a6","chat_log_uuid":"2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"}

message event data structure

FieldTypeDescription
idStringThe response ID.
objectStringThe response chunk object type. Returns chat.completion.chunk.
createdNumberThe response creation time in Unix timestamp format.
modelStringThe response model name. Defaults to sidetalk.
choicesArrayThe list of response chunks.
choices[0].indexNumberThe index of the response choice.
choices[0].delta.contentStringPart of the AI response text.
choices[0].finish_reasonString or nullThe finish reason: null while in progress, stop on completion.

Streamed response example

JSON
event: metadata
data: {"session_id":"943f15db-3984-4f21-ad64-f0115839c3a6","chat_log_uuid":"2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3"}

data: {"id":"chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3","object":"chat.completion.chunk","created":1783928563,"model":"sidetalk","choices":[{"index":0,"delta":{"content":"안녕하세요, "},"finish_reason":null}]}

data: {"id":"chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3","object":"chat.completion.chunk","created":1783928563,"model":"sidetalk","choices":[{"index":0,"delta":{"content":"무엇을 도와드릴까요?"},"finish_reason":null}]}

data: {"id":"chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3","object":"chat.completion.chunk","created":1783928563,"model":"sidetalk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: [DONE] 

Stream handling notes

  • Events are separated by \n\n.
  • event: metadata is sent once at the start of the stream.
  • Regular text responses are included in choices[0].delta.content.
  • finish_reason: stop indicates normal completion of answer generation.
  • data: [DONE] indicates that the stream has fully ended.
  • Save session_id because it is needed for subsequent conversation requests.
  • Save chat_log_uuid because it is needed when calling the feedback API.
  • showCard, inputForm, reservationBookingForm, reservationLookupForm, and pageRedirect contain structured agent response data rather than regular text.
  • Look for a chunk whose sidetalk_event.type is recommendedQuestions.
  • Get the suggested question list from sidetalk_event.data.items.
  • The ID of a suggested question is knowledgeId.

1-3. Structured event responses

Chat responses may include structured events such as cards, input forms, reservation forms, and page navigation in addition to regular text.
Structured events are data that the client UI must handle separately, rather than regular answer text.
Supported event types are:
recommended_questions is not included by default. It is returned only when recommendedQuestions: true is explicitly requested. If recommendedQuestions is omitted or false, neither the suggested question field nor events are returned.
typeDescription
showCardCard response data.
inputFormUser input form data.
reservationBookingFormReservation booking form data.
reservationLookupFormReservation lookup form data.
pageRedirectPage navigation or link guidance data.
recommendedQuestionsSuggested question data, delivered only with stream:true.

Structured events in JSON responses (stream: false)

With stream: false, structured events appear in the top-level sidetalk_events array.
sidetalk_events may be omitted when no structured events exist.

showCard example

JSON
{
  "success": true,
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion",
  "created": 1783928563,
  "model": "sidetalk",
  "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
  "chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "아래 정보를 확인해주세요."
      },
      "finish_reason": "stop"
    }
  ],
  "sidetalk_events": [
    {
      "type": "showCard",
      "data": {
        "title": "상품 안내",
        "description": "추천 상품 목록입니다.",
        "items": [
          {
            "title": "상품 A",
            "description": "상품 A 설명",
            "url": "https://example.com/product-a"
          }
        ]
      }
    }
  ]
}

inputForm example

JSON
{
  "success": true,
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion",
  "created": 1783928563,
  "model": "sidetalk",
  "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
  "chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "상담을 위해 아래 정보를 입력해주세요."
      },
      "finish_reason": "stop"
    }
  ],
  "sidetalk_events": [
    {
      "type": "inputForm",
      "data": {
        "title": "상담 정보 입력",
        "fields": [
          {
            "name": "name",
            "label": "이름",
            "type": "text",
            "required": true
          },
          {
            "name": "phone",
            "label": "연락처",
            "type": "tel",
            "required": true
          }
        ]
      }
    }
  ]
}

reservationBookingForm example

JSON
{
  "success": true,
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion",
  "created": 1783928563,
  "model": "sidetalk",
  "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
  "chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "예약을 위해 아래 정보를 입력해주세요."
      },
      "finish_reason": "stop"
    }
  ],
  "sidetalk_events": [
    {
      "type": "reservationBookingForm",
      "data": {
        "title": "예약하기",
        "form_id": "reservation_01",
        "fields": [
          {
            "name": "date",
            "label": "예약일",
            "type": "date",
            "required": true
          },
          {
            "name": "time",
            "label": "예약 시간",
            "type": "time",
            "required": true
          }
        ]
      }
    }
  ]
}

reservationLookupForm example

JSON
{
  "success": true,
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion",
  "created": 1783928563,
  "model": "sidetalk",
  "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
  "chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "예약 조회를 위해 아래 정보를 입력해주세요."
      },
      "finish_reason": "stop"
    }
  ],
  "sidetalk_events": [
    {
      "type": "reservationLookupForm",
      "data": {
        "title": "예약 조회",
        "fields": [
          {
            "name": "phone",
            "label": "연락처",
            "type": "tel",
            "required": true
          }
        ]
      }
    }
  ]
}

pageRedirect example

JSON
{
  "success": true,
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion",
  "created": 1783928563,
  "model": "sidetalk",
  "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
  "chat_log_uuid": "2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "요청하신 페이지로 이동할 수 있습니다."
      },
      "finish_reason": "stop"
    }
  ],
  "sidetalk_events": [
    {
      "type": "pageRedirect",
      "data": {
        "url": "https://example.com/order",
        "label": "주문 페이지로 이동"
      }
    }
  ]
}

Structured events in streamed responses (stream: true)

With stream: true, structured events are also delivered as chat.completion.chunk.
Regular text is included in choices[0].delta.content.
Structured events are included in sidetalk_event.

showCard example

JSON
data: {
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion.chunk",
  "created": 1783928563,
  "model": "sidetalk",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": null
    }
  ],
  "sidetalk_event": {
    "type": "showCard",
    "data": {
      "title": "상품 안내",
      "description": "추천 상품 목록입니다.",
      "items": [
        {
          "title": "상품 A",
          "description": "상품 A 설명",
          "url": "https://example.com/product-a"
        }
      ]
    }
  }
}

inputForm example

JSON
data: {
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion.chunk",
  "created": 1783928563,
  "model": "sidetalk",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": null
    }
  ],
  "sidetalk_event": {
    "type": "inputForm",
    "data": {
      "title": "상담 정보 입력",
      "fields": [
        {
          "name": "name",
          "label": "이름",
          "type": "text",
          "required": true
        },
        {
          "name": "phone",
          "label": "연락처",
          "type": "tel",
          "required": true
        }
      ]
    }
  }
}

reservationBookingForm example

JSON
data: {
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion.chunk",
  "created": 1783928563,
  "model": "sidetalk",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": null
    }
  ],
  "sidetalk_event": {
    "type": "reservationBookingForm",
    "data": {
      "title": "예약하기",
      "form_id": "reservation_01",
      "fields": [
        {
          "name": "date",
          "label": "예약일",
          "type": "date",
          "required": true
        },
        {
          "name": "time",
          "label": "예약 시간",
          "type": "time",
          "required": true
        }
      ]
    }
  }
}

reservationLookupForm example

JSON
data: {
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion.chunk",
  "created": 1783928563,
  "model": "sidetalk",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": null
    }
  ],
  "sidetalk_event": {
    "type": "reservationLookupForm",
    "data": {
      "title": "예약 조회",
      "fields": [
        {
          "name": "phone",
          "label": "연락처",
          "type": "tel",
          "required": true
        }
      ]
    }
  }
}

pageRedirect example

JSON
data: {
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion.chunk",
  "created": 1783928563,
  "model": "sidetalk",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": null
    }
  ],
  "sidetalk_event": {
    "type": "pageRedirect",
    "data": {
      "url": "https://example.com/order",
      "label": "주문 페이지로 이동"
    }
  }
}

recommendedQuestions example

JSON
data: {
  "id": "chatcmpl-2b9cc8fb-3cc6-4d40-aef6-d44af3d074f3",
  "object": "chat.completion.chunk",
  "created": 1783928563,
  "model": "sidetalk",
  "choices": [
    {
      "index": 0,
      "delta": {},
      "finish_reason": null
    }
  ],
  "sidetalk_event": {
    "type": "recommendedQuestions",
    "data": {
      "items": [
        {
          "knowledgeId": "3356",
          "question": "추천 질문1",
          "type": "chat_data"
        }
      ]
    }
  }
}

Field descriptions

sidetalk_events

FieldTypeDescription
sidetalk_eventsArrayThe list of structured events.
sidetalk_events[].typeStringThe event type.
sidetalk_events[].dataObjectData for each event.

sidetalk_event

FieldTypeDescription
sidetalk_eventObjectStructured event data.
sidetalk_event.typeStringThe event type.
sidetalk_event.dataObjectData for each event.

Handling example

JavaScript
function handleSidetalkEvent(event) {
  if (!event) return;

  const eventType = event.type;
  const eventData = event.data;

  if (eventType === "showCard") {
    console.log("카드 응답:", eventData);
  }

  if (eventType === "inputForm") {
    console.log("입력 폼:", eventData);
  }

  if (eventType === "reservationBookingForm") {
    console.log("예약 입력 폼:", eventData);
  }

  if (eventType === "reservationLookupForm") {
    console.log("예약 조회 폼:", eventData);
  }

  if (eventType === "pageRedirect") {
    console.log("페이지 이동:", eventData);
  }
  
  if (eventType === "recommendedQuestions") {
	  console.log("추천 질문:", eventData);
	}
}

Handle JSON responses

JavaScript
const events = data.sidetalk_events || [];

for (const event of events) {
  handleSidetalkEvent(event);
}

//추천 질문
const recommendedQuestions = data.recommended_questions || [];

console.log("추천 질문:", recommendedQuestions);

Handle streamed responses

JavaScript
if (data.sidetalk_event) {
  handleSidetalkEvent(data.sidetalk_event);
}

Cautions

  • The data structure of structured events may vary with site, agent, and form settings.
  • Clients should not assume a fixed structure for fields inside data.
  • Handle regular text from choices[0].message.content or choices[0].delta.content.
  • Handle structured events separately from sidetalk_events or sidetalk_event.
  • With stream: false, suggested questions are returned in the top-level recommended_questions array.
  • With stream: true, suggested questions are included in sidetalk_event.data.items.
  • sidetalk_events is used in stream: false responses.
  • sidetalk_event is used in each chunk of stream: true responses.
  • The metadata event provides session information at the start of the stream.
  • data: [DONE] means the stream has ended.

2. Conversation Feedback API

Use chat_log_uuid from the conversation response to save feedback for that conversation.
Even with v2 chat responses, the feedback API uses the existing path.

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.
chat_log_uuidStringYesThe conversation UUID received from the v2 chat/completions response.
chat_log_feedbackStringYesFeedback value: 1 means helpful; 2 means not helpful.

Example request

JSON
curl -X POST https://api.sidetalk.ai/v1/chat/feedback \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer ${API_KEY}" \
  -d '{
    "session_id": "943f15db-3984-4f21-ad64-f0115839c3a6",
    "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"
}

3. JavaScript examples


3-1. Handle JSON responses

JavaScript
async function sendMessageV2(message, sessionId = "") {
  const response = await fetch("https://api.sidetalk.ai/v2/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer [API_KEY]"
    },
    body: JSON.stringify({
      messages: [
        {
          role: "user",
          content: message
        }
      ],
      session_id: sessionId,
      stream: false
    })
  });

  const data = await response.json();

  if (!response.ok) {
    console.error("Server Error:", data.error?.message || "Unknown error");
    return null;
  }

  const answer = data.choices?.[0]?.message?.content || "";
  const finishReason = data.choices?.[0]?.finish_reason || "";
  const nextSessionId = data.session_id;
  const chatLogUuid = data.chat_log_uuid;

  console.log("AI 답변:", answer);
  console.log("finish_reason:", finishReason);
  console.log("session_id:", nextSessionId);
  console.log("chat_log_uuid:", chatLogUuid);

  return {
    answer,
    finishReason,
    sessionId: nextSessionId,
    chatLogUuid
  };
}

3-2. Handle streamed responses

JavaScript
async function sendMessageStreamV2(message, sessionId = "") {
  const response = await fetch("https://api.sidetalk.ai/v2/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer [API_KEY]"
    },
    body: JSON.stringify({
      messages: [
        {
          role: "user",
          content: message
        }
      ],
      session_id: sessionId,
      stream: true
    })
  });

  if (!response.ok) {
    const errorData = await response.json();
    console.error("Server Error:", errorData.error?.message || "Unknown error");
    return null;
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  let savedSessionId = sessionId;
  let savedChatLogUuid = "";
  let fullAnswer = "";
  let finishReason = "";
  let buffer = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });

    const blocks = buffer.split("\n\n");
    buffer = blocks.pop() || "";

    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]") {
        return {
          answer: fullAnswer,
          finishReason,
          sessionId: savedSessionId,
          chatLogUuid: savedChatLogUuid
        };
      }

      const data = JSON.parse(dataStr);

      if (eventName === "metadata") {
        savedSessionId = data.session_id;
        savedChatLogUuid = data.chat_log_uuid;
        continue;
      }

      if (eventName === "message") {
        const choice = data.choices?.[0] || {};
        const chunk = choice.delta?.content || "";

        if (chunk) {
          fullAnswer += chunk;
          console.log("chunk:", chunk);
        }

        if (choice.finish_reason) {
          finishReason = choice.finish_reason;
          console.log("finish_reason:", finishReason);
        }

        continue;
      }

      if (eventName === "showCard") {
        console.log("showCard:", data);
      }

      if (eventName === "inputForm") {
        console.log("inputForm:", data);
      }

      if (eventName === "pageRedirect") {
        console.log("pageRedirect:", data);
      }
    }
  }

  return {
    answer: fullAnswer,
    finishReason,
    sessionId: savedSessionId,
    chatLogUuid: savedChatLogUuid
  };
}

3-3. Save feedback

JavaScript
async function sendFeedback({ sessionId, chatLogUuid, isHelpful }) {
  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: isHelpful ? "1" : "2"
    })
  });

  const data = await response.json();

  if (!response.ok || !data.success) {
    console.error("Feedback Error:", data.error || data.message || "Unknown error");
    return null;
  }

  return data;
}

4. Error responses
Errors in the v2 chat API are returned in the following format.
JSON
{
  "error": {
    "message": "messages is required",
    "type": "invalid_request_error",
    "code": "message_required"
  }
}
Error responses do not include choices or finish_reason.

Main error cases

HTTP statuscodeDescription
400message_requiredmessages is missing or contains no usable role: "user" message
400invalid_session_id_formatsession_id has an invalid format
404session_id_not_foundThe provided session_id does not exist for the current site
403Authentication errorAPI authentication failure
500server_errorAn internal server error occurred

5. Notes

  • The actual question is the last role: "user" message in the messages array.
  • Previous history is not passed in messages. The server uses history stored under session_id.
  • If session_id is absent, the server issues a new one.
  • Use the session_id issued by the server.
  • If session_id is present, the server checks that the session exists for the current site.
  • For streams, save session_id and chat_log_uuid from the metadata event first.
  • Saving feedback requires both session_id and chat_log_uuid.
  • v1 /v1/chat/completions retains its original response format for compatibility.
  • Use /v2/chat/completions for automatic session creation and the v2 response structure.