Dành cho AI agent: hướng dẫn từng bước để thiết lập — /docs/agents.md, chỉ mục tài liệu — /llms.txt.
Tham chiếu API
Mọi thông tin về các yêu cầu gửi đến gateway: giao thức, địa chỉ, khóa và tham số. Dưới đây — streaming, gọi công cụ, suy luận, plugin và chi phí của yêu cầu trong phản hồi.
Giao thức và địa chỉ#
Gateway chấp nhận định dạng OpenAI và Anthropic. Base URL cho SDK OpenAI là https://gate.joingonka.ai/v1, cho SDK Anthropic là https://gate.joingonka.ai. Mọi giao thức dùng chung một key và một số dư: request ở bất kỳ định dạng nào đều đi cùng một đường.
| Phương thức và đường dẫn | Định dạng | Dùng để làm gì | Đặc điểm |
|---|---|---|---|
POST /v1/chat/completions | OpenAI Chat Completions | Chat, agent, gọi công cụ | Đường chính: các định dạng khác đều được gateway chuyển về đây. |
POST /v1/messages | Anthropic Messages | Claude Code và SDK Anthropic | Base URL không có /v1; các mô hình claude-* được thay bằng mô hình đề xuất; trường max_tokens là bắt buộc. |
POST /v1/responses | OpenAI Responses | Codex CLI và các SDK OpenAI mới | Không trạng thái: hãy gửi toàn bộ lịch sử trong mỗi request. |
POST /v1/completions | OpenAI Completions (legacy) | Tự động hoàn thành và sửa code trong editor | suffix được truyền cho mô hình như gợi ý; trong phản hồi có logprobs: null. |
POST /v1/embeddings | OpenAI Embeddings | Biểu diễn vector của văn bản | Phản hồi 501: mạng không có mô hình embedding. |
Địa chỉ tham chiếu#
Trả lời không cần key. Bảng mô hình với context và trạng thái — trong mục Mô hình.
| Phương thức và đường dẫn | Mô tả |
|---|---|
GET /v1/models | Danh sách mô hình: context, giá, tham số được hỗ trợ — các trường theo định dạng OpenRouter. |
GET /v1/models/{model} | Thông tin một mô hình; dấu gạch chéo trong id — giữ nguyên hoặc %2F. Mô hình ẩn hoặc không xác định — 404 model_not_found. |
GET /v1/capabilities | Khả năng của gateway: tham số, giao thức, plugin, trường chi phí và giới hạn (limits). |
GET /v1/plugins | Plugin: id và tên. |
GET /v1/network-status | Trạng thái các mô hình trong mạng: khả dụng, độ trễ, uptime. |
GET /v1/nodes | Tóm tắt pool node: tổng số, đang hoạt động và cách ly. |
GET /v1/web-search/engines | Web search có được bật không và các engine của nó đang ở trạng thái nào. |
Anthropic Messages#
- Base URL là
https://gate.joingonka.ai: SDK sẽ tự thêm/v1/messages. - Key nằm trong header
x-api-key(cách SDK Anthropic gửi) hoặcAuthorization: Bearer. - Các mô hình
claude-*được gateway thay bằng mô hình đề xuất (MiniMaxAI/MiniMax-M2.7); trong trườngmodelcủa phản hồi vẫn giữ tên mà client đã gửi. max_tokenslà bắt buộc, như trong API Anthropic; vượt trần của mô hình sẽ bị cắt.- Stream — sự kiện Anthropic; trong khoảng nghỉ gateway gửi
event: ping, lỗi đến qua sự kiệnevent: error. - Phần suy luận của mô hình không xuất hiện trong phản hồi: không có block
thinking. - Công cụ tích hợp
web_searchđược thực thi bởi plugin web search của gateway — xem mục Plugin. - Không có đếm token (
/v1/messages/count_tokens) — phản hồi404.
Claude Code dễ cấu hình nhất bằng trình cài đặt — kết nối công cụ. Thủ công thì dùng biến môi trường; ANTHROPIC_MODEL ghim mô hình của mạng.
export ANTHROPIC_BASE_URL=https://gate.joingonka.ai
export ANTHROPIC_AUTH_TOKEN=$JOINGONKA_API_KEY
export ANTHROPIC_MODEL=MiniMaxAI/MiniMax-M2.7
claudecurl https://gate.joingonka.ai/v1/messages \
-H "x-api-key: $JOINGONKA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2.7",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "What is Gonka?"}]
}'OpenAI Responses#
- Gateway không lưu phản hồi: hãy gửi toàn bộ lịch sử trong
input. Các trườngprevious_response_idvàconversation— lỗi400kèm mã. stoređược chấp nhận và không thay đổi gì.- Công cụ:
functionvàweb_search— công cụ sau được thực thi bởi plugin web search. Các công cụ tích hợp khác bị gateway bỏ qua và request vẫn chạy mà không có chúng; yêu cầu công cụ như vậy quatool_choice— lỗi400. - Các phần
input_imagevàinput_file— lỗi400: mô hình trong mạng chỉ làm việc với văn bản. - Các địa chỉ trạng thái (
GET /v1/responses/{id},DELETE /v1/responses/{id},GET /v1/responses/{id}/input_items,POST /v1/responses/{id}/cancel,POST /v1/responses/compact) trả về404kèm mã — gateway không lưu phản hồi. - Codex CLI: đặt id provider của bạn trong
model_provider(không phải openai) — khi đó Codex tự nén lịch sử, không cần/v1/responses/compact.
Legacy Completions#
prompt— chuỗi hoặc mảng một chuỗi; phản hồi nằm trongchoices[].text. Nhiều prompt hoặc token thay vì văn bản — lỗi400.suffixđược truyền cho mô hình như gợi ý trong prompt: mạng không có khả năng điền giữa thực sự.- Trong phản hồi có
logprobs: null;best_ofbị bỏ qua;echohoạt động.
Key và xác thực#
Key được truyền trong header Authorization: Bearer jg-… hoặc x-api-key: jg-… — trên mọi địa chỉ. Key được tạo sau khi đăng ký tại trang gate.joingonka.ai/keys.
| Tiền tố | Key | Request tới mô hình |
|---|---|---|
jg- | Key tài khoản thông thường | có |
gc- | Key con: giới hạn riêng, chi phí trừ từ số dư của chủ sở hữu | có |
gm- | Key quản lý: chỉ quản lý các key con | không — 403 forbidden |
- Mỗi key trong trang cá nhân có thể đặt giới hạn chi tiêu theo ngày, tháng và tổng; vượt quá —
402 child_key_limit_exceeded. - Số request mỗi phút cho mỗi key bị giới hạn — giá trị trong mục Giới hạn.
- Không có key thì chỉ demo chat trên site hoạt động: request không key từ code của bạn sẽ nhận
402vớiis_demo. - Key chỉ được quản lý trong trang cá nhân:
/api/keysvới API key không khả dụng. Số dư và chi tiêu theo key — API tài khoản.
Khóa là bí mật: đừng lưu trong repository hay code frontend, hãy truyền qua biến môi trường.
Ví dụ#
Cùng một yêu cầu trong bốn SDK. Model là model khuyến nghị (MiniMaxAI/MiniMax-M2.7), khóa lấy từ biến môi trường JOINGONKA_API_KEY.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://gate.joingonka.ai/v1",
api_key=os.environ["JOINGONKA_API_KEY"],
)
response = client.chat.completions.create(
model="MiniMaxAI/MiniMax-M2.7",
messages=[{"role": "user", "content": "What is Gonka?"}],
)
print(response.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://gate.joingonka.ai/v1",
apiKey: process.env.JOINGONKA_API_KEY,
});
const response = await client.chat.completions.create({
model: "MiniMaxAI/MiniMax-M2.7",
messages: [{ role: "user", content: "What is Gonka?" }],
});
console.log(response.choices[0].message.content);curl https://gate.joingonka.ai/v1/chat/completions \
-H "Authorization: Bearer $JOINGONKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is Gonka?"}]
}'import os
import anthropic
client = anthropic.Anthropic(
base_url="https://gate.joingonka.ai",
api_key=os.environ["JOINGONKA_API_KEY"],
)
message = client.messages.create(
model="MiniMaxAI/MiniMax-M2.7",
max_tokens=1024,
messages=[{"role": "user", "content": "What is Gonka?"}],
)
print(message.content[0].text)Phản hồi dạng stream#
import os
from openai import OpenAI
client = OpenAI(base_url="https://gate.joingonka.ai/v1", api_key=os.environ["JOINGONKA_API_KEY"])
stream = client.chat.completions.create(
model="MiniMaxAI/MiniMax-M2.7",
messages=[{"role": "user", "content": "What is Gonka?"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://gate.joingonka.ai/v1", apiKey: process.env.JOINGONKA_API_KEY });
const stream = await client.chat.completions.create({
model: "MiniMaxAI/MiniMax-M2.7",
messages: [{ role: "user", content: "What is Gonka?" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}curl -N https://gate.joingonka.ai/v1/chat/completions \
-H "Authorization: Bearer $JOINGONKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is Gonka?"}],
"stream": true
}'import os
import anthropic
client = anthropic.Anthropic(base_url="https://gate.joingonka.ai", api_key=os.environ["JOINGONKA_API_KEY"])
with client.messages.stream(
model="MiniMaxAI/MiniMax-M2.7",
max_tokens=1024,
messages=[{"role": "user", "content": "What is Gonka?"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Tham số yêu cầu#
Các tham số POST /v1/chat/completions mà gateway tự đảm bảo — danh sách supported_parameters trong phản hồi capabilities:
| Tham số | Mô tả |
|---|---|
temperature | Độ ngẫu nhiên của câu trả lời: càng cao càng đa dạng. |
top_p | Chọn token theo tổng xác suất. |
top_k | Chọn từ k token có xác suất cao nhất. |
min_p | Cắt bỏ các token ít khả năng so với token khả năng nhất. |
frequency_penalty | Phạt việc lặp lại thường xuyên. |
presence_penalty | Phạt các token đã xuất hiện trước đó. |
repetition_penalty | Hệ số chống lặp lại. |
stop | Các chuỗi mà tại đó quá trình sinh dừng lại. |
seed | Seed để tái tạo kết quả. |
max_tokens | Giới hạn token của phản hồi; vượt trần model sẽ bị cắt về trần. |
max_completion_tokens | Tên khác của max_tokens: gateway chuyển giá trị vào đó. |
tools | Các hàm mà model có thể gọi, theo định dạng OpenAI. |
tool_choice | Có gọi hàm không: để model chọn, không bao giờ, bắt buộc hoặc một hàm cụ thể. |
response_format | Phản hồi có cấu trúc: json_object hoặc json_schema. |
- Không có
temperature, gateway thay bằng0.7. - Không có
max_tokens, gateway thay bằng mặc định của model: không stream thì ngắn hơn, khi stream thì bằng trần model. Số cụ thể theo model — trong mục Giới hạn.
Được truyền nguyên vẹn vào mạng#
reasoning_effort, reasoning, enable_thinking, chat_template_kwargs, thinking_token_budget, min_tokens, logit_bias, n, parallel_tool_calls, extra_body. Gateway không kiểm tra chúng: giá trị ngoài danh sách của mạng sẽ gây lỗi 400 với type api_error.
Không được truyền vào mạng#
Các trường còn lại gateway nhận nhưng không truyền vào mạng — ví dụ user, metadata, store, logprobs, top_logprobs, thinking, stream_options, web_search_options. usage trong stream luôn được gửi.
Streaming#
stream: true— phản hồi dưới dạng sự kiện SSE; sự kiện cuối làdata: [DONE].- Trước khi kết thúc luôn có một chunk chứa
usage— kể cả khi không cóstream_options. - Trong lúc tạm dừng, gateway cứ mỗi 15 giây gửi comment
: keep-alive— các SSE client sẽ bỏ qua. - Khi stream chưa mở, lỗi đến dưới dạng mã phản hồi thông thường; sau khi mở, lỗi đến dưới dạng chunk
joingonka-error. - Trong
delta.tool_calls— một lệnh gọi mỗi chunk: các lệnh gọi bị mạng gộp lại sẽ được gateway tách ra.
data: {"object":"chat.completion.chunk","model":"MiniMaxAI/MiniMax-M2.7","choices":[{"index":0,"delta":{"content":"Hi"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"MiniMaxAI/MiniMax-M2.7","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"object":"chat.completion.chunk","model":"MiniMaxAI/MiniMax-M2.7","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":2,"total_tokens":14}}
data: [DONE]Các chunk dịch vụ của gateway#
Có thể nhận biết chúng qua trường id:
id | Khi nào và bên trong có gì |
|---|---|
joingonka-error | Sự cố sau khi mở stream: trường error, sau đó ngắt kết nối không có [DONE]. |
joingonka-stream-stalled | Mạng im lặng lâu hơn khoảng tạm dừng cho phép: stream đóng với finish_reason: stop. |
joingonka-stream-unfinished | Mạng ngắt quá trình sinh: finish_reason: length — hãy tiếp tục bằng yêu cầu tiếp theo. |
joingonka-citations | Nguồn tìm kiếm web trong delta.annotations — trước khi kết thúc. |
joingonka-meta | Chi phí và thời gian — chỉ khi có header x-joingonka-meta: 1. |
Stream trong các giao thức khác#
- Anthropic Messages: sự kiện từ
message_startđếnmessage_stop, khi tạm dừng làevent: ping, sự cố làevent: error. - OpenAI Responses: sự kiện
response.*, sự cố làresponse.failed. - Legacy Completions: khi sự cố —
data: {"error": …}, sau đó[DONE].
Gọi công cụ#
- Định dạng OpenAI:
toolsvàtool_choice. Định dạng cũfunctionsvàfunction_callcũng được chấp nhận — phản hồi sẽ ở đúng định dạng đó. - Trong stream — một lệnh gọi mỗi chunk: các client chỉ đọc phần tử đầu tiên sẽ không mất lệnh gọi nào.
- Lịch sử mà mạng sẽ trả lỗi
400sẽ được gateway sửa: roledeveloperthànhsystem, các id lệnh gọi trống hoặc trùng lặp được cấp id duy nhất,argumentsdạng object chuyển thành chuỗi JSON,typebị thiếu được bổ sung, lệnh gọi không có tên bị loại bỏ cùng với kết quả. - Lệnh gọi mà model viết dưới dạng markup trong văn bản sẽ được gateway chuyển vào
tool_calls; các lệnh gọi giả trong phản hồi của yêu cầu không có công cụ sẽ bị loại bỏ. - Quá trình sinh bị ngắt giữa chừng phần tham số — sẽ nhận
finish_reason: length, không phảitool_calls: hãy tăng giới hạn phản hồi.
{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is the weather in Paris?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}]
}Giới hạn của JSON-Schema#
Schema của công cụ và response_format được mạng biên dịch thành grammar; biểu thức chính quy dùng engine RE2. Gateway đưa schema về dạng mà mạng chấp nhận:
$refđược mở rộng tại chỗ, các mục$defsvàdefinitionsbị xóa; tham chiếu đệ quy trở thành schema không có ràng buộc.patternchứa các cấu trúc không có trong RE2 (lookahead, lookbehind, backreference, atomic group, quantifier siêu tham lam) sẽ bị gỡ bỏ; các lần lặp trên 1000 bị rút xuống 1000.anyOfvàoneOftừ các hằng số được gộp thànhenum; nếu số nhánh không gộp được nhiều hơn 16, phần hợp nhất sẽ bị gỡ bỏ.
Schema có thể trở nên lỏng hơn so với ban đầu — hãy tự kiểm tra tham số lệnh gọi ở phía bạn.
Phản hồi có cấu trúc#
response_format: {"type": "json_object"} — phản hồi là JSON hợp lệ, {"type": "json_schema", "json_schema": {"name": …, "schema": …}} — theo schema của bạn với các giới hạn ở trên. JSON bị cắt mà không stream sẽ được plugin response-healing sửa.
{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "Name three planets."}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "planets",
"schema": {
"type": "object",
"properties": {"planets": {"type": "array", "items": {"type": "string"}}},
"required": ["planets"]
}
}
}
}Suy luận#
- Suy luận của model đến tách biệt với phản hồi:
message.reasoning_content, trong stream làdelta.reasoning_content. Trườngreasoningđược gateway đổi tên thành định dạng này. - Suy luận tiêu tốn
max_tokens: với giới hạn nhỏ, phản hồi bị ngắt (finish_reason: length) ngay cả trước phần văn bản. - Nếu không có văn bản phản hồi mà có suy luận, gateway chuyển chúng vào
content— trừ các phản hồi có gọi công cụ. reasoning_effortvàreasoning.effortđược truyền vào mạng. Nếu model chỉ có hai chế độ, gateway đưa giá trị về chúng:nonevàminimal→low, các mức cao hơn → suy luận mặc định.- Nếu node từ chối giá trị, gateway hạ nó xuống (
maxvàxhigh→high,minimal→low, nếu không thì gỡ trường) và gửi lại yêu cầu. - Trong
/v1/messages, suy luận không được truyền — không có blockthinking.
Plugin#
Plugin được bật bằng trường plugins — mảng chuỗi hoặc object có options. Danh sách — GET /v1/plugins.
| Plugin | Mô tả | Điều kiện |
|---|---|---|
response-healing | Sửa JSON bị cắt trong phản hồi của model. | Chỉ khi không stream và phản hồi bắt đầu bằng { hoặc [. |
privacy-sanitization | Che trong tin nhắn văn bản: email, IPv4, số thẻ, JWT, khóa hex 64 ký tự và khóa dạng sk-…, gw_…, gm-…, Bearer …. | Chế độ — trường privacy_mode: redact (mặc định) hoặc tokenize. |
file-parser | Trích xuất văn bản từ PDF. | Nếu toàn bộ nội dung tin nhắn là PDF dạng base64: data:application/pdf;base64,… hoặc không có tiền tố. |
web | Tìm kiếm web: kết quả được trộn vào yêu cầu, phản hồi nhận liên kết nguồn. | Kết hợp với privacy-sanitization — lỗi 400. |
Tìm kiếm web#
- Tùy chọn:
max_results— từ 1 đến 10, mặc định 5;engine— gợi ý engine;search_prompt— văn bản riêng trước kết quả;enabled: false— tắt tìm kiếm. - Nguồn — trong
message.annotations[].url_citation; trong stream — chunkjoingonka-citationstrước khi kết thúc. mode: "agent"— model tự quyết định có tìm kiếm hay không và tìm gì;max_searches— từ 1 đến 5, mặc định 3.- Thanh toán: ở chế độ thông thường — chỉ tính token (kết quả tìm kiếm được tính vào token đầu vào); ở chế độ agent — token của tất cả các bước cộng thêm 1000 nGNK cho mỗi lần tìm kiếm được thực hiện (
x_joingonka.web_search_surcharge_ngonka). - Trong Anthropic Messages và OpenAI Responses, công cụ tích hợp
web_searchthực thi chính plugin này ở chế độ agent.
{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
"plugins": [{"id": "web", "max_results": 5}]
}{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
"plugins": [{"id": "web", "mode": "agent", "max_searches": 3}]
}Chi phí và các trường hệ thống#
Phản hồi không streaming mang theo chi phí của yêu cầu trong usage:
| Trường | Mô tả |
|---|---|
usage.cost_gnk | Chi phí yêu cầu tính bằng GNK |
usage.platform_fee_gnk | Trong đó — phí nền tảng, GNK |
usage.total_cost_gnk | Tổng số tiền trừ, tính bằng GNK |
usage.total_cost_usd | Tổng số tiền tính bằng USD theo tỷ giá GNK hiện tại |
- Trong stream,
usagechỉ chứa token; chi phí nằm trong chunkjoingonka-meta. - Với header
x-joingonka-meta: 1, phản hồiPOST /v1/chat/completionsnhận được blockx_joingonka: chi phí (cost_ngonka), số dư sau khi trừ (balance_ngonka, chỉ khi không streaming) và thời gian (ttft_ms). Các giao thức khác không trả về block này. x-request-id— mã định danh yêu cầu: hãy gửi kèm khi liên hệ hỗ trợ.Retry-Afterđi kèm với429: cần chờ bấy nhiêu giây trước khi thử lại.- Các header
X-TitlevàHTTP-Referer(giống OpenRouter) giúp gateway nhận diện ứng dụng của bạn; nội dung của chúng không được lưu lại.
Giới hạn#
- Hình ảnh: các phần
image_urlđược thay bằng văn bản giữ chỗ — model không nhìn thấy hình (vision: falsetrong phần khả năng). - Từ trình duyệt, API chỉ truy cập được từ các tên miền JoinGonka (kiểm tra
Origin): hãy gọi nó từ server của bạn, đừng đặt key ở frontend. - Embeddings:
POST /v1/embeddingstrả về501— mạng không có model embedding. - Mã lỗi, giới hạn và timeout — trong mục Lỗi và giới hạn.