Chat API
Tạo response, streaming SSE, upload tệp, đọc hội thoại và gửi feedback.
Base URL trong ví dụ là $ASSISTANT_API_URL. Mọi endpoint cần Bearer key và đúng scope.
Tạo chat response
POST /v1/chat/responses · scope chat:write
{
"external_user_id": "customer_42",
"input": "Tóm tắt chính sách đổi trả.",
"conversation_id": "a12d5e41-7ab7-4c8f-b024-c2c38b5c43f4",
"file_ids": ["8d50c5c2-bf85-48a4-b252-8dc97410452c"],
"model": "optional-model-code",
"stream": false
}| Field | Bắt buộc | Giới hạn và ý nghĩa |
|---|---|---|
external_user_id | Có | 1–256 ký tự; identity ổn định trong phạm vi trợ lý. |
input | Có | 1–100.000 ký tự. |
conversation_id | Không | UUID của hội thoại thuộc cùng external user. Bỏ qua để tạo hội thoại mới. |
file_ids | Không | Tối đa 10 UUID đã upload bởi cùng external user. |
model | Không | Model override; chỉ hoạt động nếu plan của owner cho phép. |
stream | Không | Mặc định false; đặt true để nhận SSE. |
Request không streaming trả JSON 200. Nếu retry một request đã hoàn tất với cùng idempotency key, API trả lại metadata đã lưu với 200 kèm header Idempotent-Replayed: true; token không bao giờ được phát lại. Idempotency-Key tối đa 255 ký tự.
Streaming bằng SSE
curl -N "$ASSISTANT_API_URL/v1/chat/responses" \
--request POST \
--header "Authorization: Bearer $ASSISTANT_API_KEY" \
--header "Accept: text/event-stream" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: stream-customer-42-001" \
--data "{
\"external_user_id\": \"$EXTERNAL_USER_ID\",
\"input\": \"Giải thích các bước cài đặt.\",
\"stream\": true
}"Mỗi event có dạng:
event: response.output_text.delta
data: {"type":"response.output_text.delta","sequence":3,"response_id":"resp_...","delta":"Xin chào"}
Event response.created xuất hiện đầu tiên. sequence tăng dần; stream kết thúc bằng đúng một response.completed hoặc error. Dòng : heartbeat có thể xuất hiện mỗi khoảng 15 giây và không có sequence.
| Event | Nội dung chính |
|---|---|
response.created | Response đã bắt đầu. |
conversation.created | conversation_id mới. |
response.output_text.delta | Phần text trong delta. |
response.reasoning.delta | Phần reasoning nếu model cung cấp. |
response.tool_call.started | Tool call đã bắt đầu. |
response.tool_call.completed | Tool call đã hoàn tất. |
response.file.created | Tệp do response tạo. |
response.completed | Terminal event thành công, gồm message_id. |
error | Terminal event lỗi. |
Parser phải ghép nhiều delta theo sequence và xử lý Unicode bị chia giữa network chunks. Không giả định mỗi TCP chunk chứa trọn một SSE event.
Ví dụ parser Node.js/TypeScript
Ví dụ này giữ buffer giữa các network chunks và dùng streaming TextDecoder để không làm hỏng Unicode:
const response = await fetch(`${process.env.ASSISTANT_API_URL}/v1/chat/responses`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ASSISTANT_API_KEY}`,
Accept: "text/event-stream",
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
external_user_id: "customer_42",
input: "Giải thích các bước cài đặt.",
stream: true,
}),
})
if (!response.ok || !response.body) {
throw new Error(`Chat request failed: ${response.status}`)
}
const reader = response.body.getReader()
const decoder = new TextDecoder()
let buffer = ""
for (;;) {
const { value, done } = await reader.read()
buffer += decoder.decode(value, { stream: !done })
let boundary
while ((boundary = buffer.indexOf("\n\n")) >= 0) {
const block = buffer.slice(0, boundary)
buffer = buffer.slice(boundary + 2)
if (!block || block.startsWith(":")) continue
const data = block
.split("\n")
.filter((line) => line.startsWith("data:"))
.map((line) => line.slice(5).trimStart())
.join("\n")
if (!data) continue
const event = JSON.parse(data)
if (event.type === "response.output_text.delta") {
process.stdout.write(event.delta)
} else if (event.type === "error") {
throw new Error(event.message ?? "Stream failed")
}
}
if (done) break
}Idempotency
Idempotency-Key là optional nhưng nên dùng cho mọi request tạo chat:
- Dùng một key duy nhất cho mỗi thao tác logic.
- Cùng key và cùng body khi request đang chạy trả
409 REQUEST_IN_PROGRESS. - Cùng key nhưng body khác trả
409 IDEMPOTENCY_CONFLICT. - Metadata hoàn tất được giữ 24 giờ; lease đang chạy hết hạn sau 10 phút.
- Retry stream không phát lại token đã nhận. Kết quả replay có
idvàmessage_id; lấy nội dung bằngGET /v1/responses/{id}.
Lấy lại response
GET /v1/responses/{response_id} · scope chat:write
curl "$ASSISTANT_API_URL/v1/responses/$RESPONSE_ID?external_user_id=$EXTERNAL_USER_ID" \
--header "Authorization: Bearer $ASSISTANT_API_KEY"Dùng để lấy lại kết quả khi kết nối SSE bị ngắt. Response chỉ có sau khi hoàn tất; trước đó API trả 404 RESPONSE_NOT_FOUND. status là completed, failed hoặc incomplete (client ngắt kết nối trước khi hoàn tất).
Upload tệp
POST /v1/files · scope files:write · multipart/form-data
curl "$ASSISTANT_API_URL/v1/files" \
--request POST \
--header "Authorization: Bearer $ASSISTANT_API_KEY" \
--form "external_user_id=$EXTERNAL_USER_ID" \
--form "file=@./policy.pdf"{
"id": "8d50c5c2-bf85-48a4-b252-8dc97410452c",
"object": "file",
"filename": "policy.pdf",
"bytes": 182400,
"mime_type": "application/pdf"
}Kích thước tối đa là 25 MiB. Hỗ trợ PDF, DOCX, XLSX, CSV, TXT và image MIME types. Sau khi upload, truyền id trong file_ids của chat request cho cùng external user.
Đọc hội thoại
GET /v1/conversations/{conversation_id} · scope conversations:read
curl "$ASSISTANT_API_URL/v1/conversations/$CONVERSATION_ID?external_user_id=$EXTERNAL_USER_ID" \
--header "Authorization: Bearer $ASSISTANT_API_KEY"API trả 404 CONVERSATION_NOT_FOUND nếu assistant hoặc external user không sở hữu hội thoại.
Phân trang tin nhắn
GET /v1/conversations/{conversation_id}/messages · scope conversations:read
curl "$ASSISTANT_API_URL/v1/conversations/$CONVERSATION_ID/messages?external_user_id=$EXTERNAL_USER_ID&limit=50" \
--header "Authorization: Bearer $ASSISTANT_API_KEY"limit từ 1–100, mặc định 50. Tin nhắn sắp xếp từ cũ đến mới. Khi has_more là true, gửi last_id ở query parameter after của request kế tiếp. Cursor thuộc hội thoại khác trả 400 INVALID_CURSOR.
{
"object": "list",
"data": [
{
"id": "b0f16c77-a275-46c8-9dc8-8fe9fd5991cc",
"object": "message",
"role": "assistant",
"content": "Nội dung phản hồi...",
"created_at": "2026-08-13T08:30:00Z"
}
],
"has_more": true,
"first_id": "b0f16c77-a275-46c8-9dc8-8fe9fd5991cc",
"last_id": "b0f16c77-a275-46c8-9dc8-8fe9fd5991cc"
}Gửi feedback
POST /v1/messages/{message_id}/feedback · scope feedback:write
curl "$ASSISTANT_API_URL/v1/messages/$MESSAGE_ID/feedback" \
--request POST \
--header "Authorization: Bearer $ASSISTANT_API_KEY" \
--header "Content-Type: application/json" \
--data "{\"external_user_id\":\"$EXTERNAL_USER_ID\",\"rating\":\"up\"}"rating chỉ nhận up hoặc down. Thành công trả 204 No Content.
Xóa end user
DELETE /v1/users/{external_user_id} · scope users:delete
curl "$ASSISTANT_API_URL/v1/users/$EXTERNAL_USER_ID" \
--request DELETE \
--header "Authorization: Bearer $ASSISTANT_API_KEY"Xóa vĩnh viễn hội thoại, tin nhắn, bộ nhớ, tệp đã tải lên và dữ liệu usage của external user trong trợ lý này. Dùng cho yêu cầu xóa tài khoản hoặc xóa dữ liệu cá nhân. API idempotent và trả 204 No Content, kể cả khi user chưa từng tồn tại. Dữ liệu billing của owner không bị ảnh hưởng.