Bỏ qua, tới nội dung chính

API Reference

API Reference

Toàn bộ API công khai nằm ở https://api.chattudong.com. Endpoint gọi model được thiết kế tương thích OpenAI nên bạn dùng lại thư viện sẵn có, không phải học gì mới.

Xác thực

Mọi request tới /v1 phải mang API key của tổ chức. Tạo key trong dashboard ở Cài đặt → Khoá API (/dashboard/cai-dat). Key có dạng ck_live_ cho môi trường thật và ck_test_ cho môi trường thử.

Header xác thực
Authorization: Bearer ck_live_xxxxxxxxxxxxxxxxxxxxxxxx

# Hoặc, nếu thư viện của bạn không cho đổi header Authorization:
X-Api-Key: ck_live_xxxxxxxxxxxxxxxxxxxxxxxx

Vài điều nên biết trước khi tích hợp:

  • Key thô chỉ hiện đúng một lần lúc tạo. Cơ sở dữ liệu chỉ lưu SHA-256 của key, nên không có đường “xem lại”. Mất thì thu hồi và tạo cái mới.
  • Key gắn với tổ chức, không gắn với người. Nhân sự nghỉ việc không làm chết tích hợp.
  • Đặt được scopes và số ngày hết hạn khi tạo. Key thiếu scope sẽ nhận 403 insufficient_scope.
  • Thu hồi có hiệu lực ngay ở request kế tiếp.

GET /v1/models

Trả về danh sách model đang bật cho tổ chức bạn, theo đúng khung list của OpenAI và có thêm vài trường riêng để bạn dựng giao diện chọn model.

Yêu cầu
curl https://api.chattudong.com/v1/models \
  -H "Authorization: Bearer $CHATLY_API_KEY"
Phản hồi (rút gọn)
{
  "object": "list",
  "data": [
    {
      "id": "local/gemma-3-12b",
      "object": "model",
      "created": 1750000000,
      "owned_by": "local",
      "display_name": "Gemma 3 12B",
      "friendly_name": "Tiết kiệm",
      "tier": "economy",
      "context_window": 128000,
      "vn_hosted": true
    }
  ]
}

owned_by là provider: openai, anthropic, google, xai hoặc local. vn_hosted cho biết model chạy trên máy chủ đặt tại Việt Nam — dùng để lọc khi tổ chức yêu cầu dữ liệu không rời lãnh thổ.

POST /v1/chat/completions

Endpoint chính. Nhận đúng định dạng OpenAI; những trường lạ trong body được bỏ qua thay vì báo lỗi, nên SDK phiên bản mới hơn cũng không làm hỏng tích hợp.

Tham số

TênKiểuGhi chú
modelstring · bắt buộcId model lấy từ GET /v1/models, ví dụ local/gemma-3-12b.
messagesarray · bắt buộcTối thiểu 1 phần tử. Mỗi phần tử có role (system | user | assistant | tool) và content dạng chuỗi, tối đa 200.000 ký tự.
temperaturenumber · 0…2Càng thấp càng bám sát tài liệu. Bỏ trống thì dùng mặc định của model.
max_tokensinteger · 1…200000Trần token sinh ra. Cũng là trần chi phí ước tính bị giữ trước.
top_pnumber · 0…1Nucleus sampling. Thường chỉ chỉnh một trong hai: top_p hoặc temperature.
stopstring[]Danh sách chuỗi dừng.
streambooleantrue để nhận SSE từng mẩu thay vì đợi trả lời đầy đủ.

Header tuỳ chọn

HeaderTác dụng
x-chatly-use-byokĐặt true để dùng khoá provider riêng của tổ chức — lần gọi đó không trừ credits. Xem BYOK.
Idempotency-KeyDùng trên các request có tính tiền để gửi lại an toàn sau khi mạng đứt. Gửi lại cùng khoá với nội dung khác sẽ nhận 409 idempotency_key_reused.

Ví dụ — không streaming

Terminal
curl https://api.chattudong.com/v1/chat/completions \
  -H "Authorization: Bearer $CHATLY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "local/gemma-3-12b",
    "messages": [
      {"role": "system", "content": "Bạn là trợ lý của một cửa hàng thời trang. Trả lời ngắn gọn, lịch sự."},
      {"role": "user", "content": "Shop mở cửa mấy giờ?"}
    ],
    "temperature": 0.3,
    "max_tokens": 512
  }'
Phản hồi
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "created": 1750000000,
  "model": "local/gemma-3-12b",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Shop mở cửa từ 9h đến 21h mỗi ngày ạ." },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 48, "completion_tokens": 17, "total_tokens": 65 },
  "chatly": { "charged_micros": "1830", "byok": false }
}

Khối chatly là phần mở rộng ngoài chuẩn OpenAI: charged_micros là số tiền đã trừ tính theo micro (một phần triệu đơn vị tiền, trả về dạng chuỗi để không mất chính xác), byok cho biết lần gọi đó có dùng khoá riêng của bạn hay không. SDK OpenAI bỏ qua trường lạ nên khối này không làm hỏng gì.

Ví dụ — streaming (SSE)

Đặt "stream": true. Phản hồi là chuỗi sự kiện chat.completion.chunk: mẩu đầu mang role, các mẩu sau mang delta.content, mẩu áp chót mang finish_reason, mẩu cuối mang usage để bạn đối soát, rồi kết thúc bằng [DONE].

Luồng SSE (rút gọn)
data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Shop mở cửa"},"finish_reason":null}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":48,"completion_tokens":17,"total_tokens":65},"chatly":{"charged_micros":"1830","byok":false}}

data: [DONE]

Hình dạng lỗi

Mọi lỗi ra khỏi API đều có cùng một hình dạng. Đây là hợp đồng: bạn switch-case theo error.code được, không phải parse chuỗi tiếng Việt.

ApiErrorBody
{
  "error": {
    "code": "insufficient_credits",
    "message": "Ví của tổ chức không đủ credits cho lần gọi này",
    "field": "model",        // chỉ có khi lỗi validate
    "docsUrl": "https://chattudong.com/docs/api-reference",  // chỉ có khi trỏ được tới mục cụ thể
    "retryAfter": 42,        // chỉ có với 429 / 503, đơn vị giây
    "requestId": "req_…"     // LUÔN có
  }
}
  • code — mã ổn định, xem bảng bên dưới. Đổi tên mã là breaking change nên chúng tôi không đổi lặng lẽ.
  • message — viết cho người đang đọc log lúc 2 giờ sáng: nói rõ chuyện gì xảy ra và làm gì tiếp theo.
  • requestId — dán vào ticket hỗ trợ, chúng tôi tra được đúng request đó.
  • Với 429503, giá trị retryAfter cũng được trả ở header HTTP Retry-After.

Bảng mã lỗi đầy đủ

Đây là toàn bộ mã lỗi công khai, không có mã nào nằm ngoài bảng này.

HTTPNghĩa và cách xử lý
invalid_request400Body hoặc tham số không hợp lệ. Trường sai được ghi ở error.field.
unsupported_model400Model không tồn tại hoặc tổ chức của bạn chưa được bật. Tra lại bằng GET /v1/models.
context_too_long400Tổng hội thoại vượt cửa sổ ngữ cảnh của model. Cắt bớt lịch sử hoặc đổi model có context lớn hơn.
unauthenticated401Thiếu thông tin xác thực — không có API key và cũng không có phiên đăng nhập hợp lệ.
invalid_api_key401Key sai định dạng, không tồn tại hoặc đã hết hạn.
api_key_revoked401Key từng hợp lệ nhưng đã bị thu hồi. Tạo key mới trong Cài đặt.
insufficient_scope403Key hợp lệ nhưng không có scope cần thiết cho thao tác này.
forbidden403Không đủ quyền — sai vai trò, hoặc tài nguyên thuộc tổ chức khác.
insufficient_credits402Ví hết tiền. Nạp thêm rồi gọi lại; chúng tôi không ghi nợ.
organization_suspended402Tổ chức đang bị tạm ngưng. Liên hệ hỗ trợ để mở lại.
plan_limit_exceeded402Chạm hạn mức của gói hiện tại (số kênh, dung lượng kho kiến thức…).
not_found404Không có tài nguyên với id đó trong tổ chức của bạn.
conflict409Xung đột trạng thái — thường là trùng tên hoặc bản ghi đã tồn tại.
idempotency_key_reused409Idempotency-Key đã dùng cho một request có nội dung khác. Đổi khoá mới.
channel_needs_reauth422Token của kênh hết hạn hoặc bị thu hồi phía nền tảng. Kết nối lại kênh.
service_window_expired422Quá cửa sổ được phép nhắn chủ động của nền tảng (ví dụ 24 giờ của Meta).
template_required422Ngoài cửa sổ dịch vụ, nền tảng chỉ cho gửi mẫu tin đã duyệt.
rate_limited429Vượt số yêu cầu mỗi phút của gói. Xem header Retry-After rồi thử lại.
internal_error500Lỗi phía chúng tôi. Gửi error.requestId cho hỗ trợ để tra đúng dòng log.
provider_error502Nhà cung cấp model trả lỗi, hoặc provider chưa được cấu hình khoá.
provider_overloaded503Nhà cung cấp đang quá tải. Thử lại sau, có thể kèm backoff.
provider_timeout504Nhà cung cấp không phản hồi kịp. Thử lại hoặc giảm max_tokens.

Giới hạn tần suất

Giới hạn tính theo tổ chức, cửa sổ cố định 60 giây. Số yêu cầu mỗi phút phụ thuộc gói bạn đang dùng; vượt thì nhận 429 rate_limited kèm Retry-After cho biết còn bao nhiêu giây nữa sang cửa sổ mới.

Cách xử lý đúng là đợi đúng Retry-After rồi thử lại, có jitter nếu bạn chạy nhiều worker song song. Đừng thử lại ngay lập tức trong vòng lặp — cửa sổ chưa đổi thì kết quả vẫn thế.

Các nhóm endpoint khác

Ngoài /v1, API còn các nhóm phục vụ dashboard và tích hợp sâu hơn. Chúng dùng phiên đăng nhập hoặc API key có scope tương ứng:

NhómDùng để
/api-keysTạo, liệt kê và thu hồi API key của tổ chức.
/provider-keysQuản lý khoá BYOK — chỉ vai trò quản trị trở lên.
/agentsTrợ lý: model, chỉ dẫn hệ thống, kho kiến thức gắn kèm.
/knowledge-basesKho kiến thức và tài liệu bên trong.
/channelsKênh nhắn tin và thông tin kết nối nền tảng.
/conversationsHội thoại, tin nhắn, chuyển cho nhân viên.
/walletSố dư, lịch sử giao dịch, chi phí từng lần gọi model.
/widget/{channelId}API công khai cho web widget, chặn theo domain.
/webhooks/*Điểm nhận tin từ các nền tảng, xác thực bằng chữ ký.

Đặc tả OpenAPI được sinh thẳng từ mã nguồn nên không bao giờ lệch với thực tế — xem tại https://api.chattudong.com/docs.