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ạngDùng để làm gìĐặc điểm
POST /v1/chat/completionsOpenAI Chat CompletionsChat, 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/messagesAnthropic MessagesClaude Code và SDK AnthropicBase 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/responsesOpenAI ResponsesCodex CLI và các SDK OpenAI mớiKhông trạng thái: hãy gửi toàn bộ lịch sử trong mỗi request.
POST /v1/completionsOpenAI Completions (legacy)Tự động hoàn thành và sửa code trong editorsuffix được truyền cho mô hình như gợi ý; trong phản hồi có logprobs: null.
POST /v1/embeddingsOpenAI EmbeddingsBiểu diễn vector của văn bảnPhả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ẫnMô tả
GET /v1/modelsDanh 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/capabilitiesKhả năng của gateway: tham số, giao thức, plugin, trường chi phí và giới hạn (limits).
GET /v1/pluginsPlugin: id và tên.
GET /v1/network-statusTrạng thái các mô hình trong mạng: khả dụng, độ trễ, uptime.
GET /v1/nodesTóm tắt pool node: tổng số, đang hoạt động và cách ly.
GET /v1/web-search/enginesWeb 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ặc Authorization: Bearer.
  • Các mô hình claude-* được gateway thay bằng mô hình đề xuất (MiniMaxAI/MiniMax-M2.7); trong trường model của phản hồi vẫn giữ tên mà client đã gửi.
  • max_tokens là 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ện event: 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ồi 404.

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
claude

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ường previous_response_id và conversation — lỗi 400 kèm mã.
  • store được chấp nhận và không thay đổi gì.
  • Công cụ: function và 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 qua tool_choice — lỗi 400.
  • Các phần input_image và input_file — lỗi 400: 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ề 404 kè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 trong choices[].text. Nhiều prompt hoặc token thay vì văn bản — lỗi 400.
  • 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_of bị bỏ qua; echo hoạ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ốKeyRequest tới mô hình
jg-Key tài khoản thông thườngcó
gc-Key con: giới hạn riêng, chi phí trừ từ số dư của chủ sở hữucó
gm-Key quản lý: chỉ quản lý các key conkhô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 402 với is_demo.
  • Key chỉ được quản lý trong trang cá nhân: /api/keys vớ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)

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)

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_pChọn token theo tổng xác suất.
top_kChọn từ k token có xác suất cao nhất.
min_pCắt bỏ các token ít khả năng so với token khả năng nhất.
frequency_penaltyPhạt việc lặp lại thường xuyên.
presence_penaltyPhạt các token đã xuất hiện trước đó.
repetition_penaltyHệ số chống lặp lại.
stopCác chuỗi mà tại đó quá trình sinh dừng lại.
seedSeed để tái tạo kết quả.
max_tokensGiới hạn token của phản hồi; vượt trần model sẽ bị cắt về trần.
max_completion_tokensTên khác của max_tokens: gateway chuyển giá trị vào đó.
toolsCác hàm mà model có thể gọi, theo định dạng OpenAI.
tool_choiceCó 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_formatPhản hồi có cấu trúc: json_object hoặc json_schema.
  • Không có temperature, gateway thay bằng 0.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.
SSE
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:

idKhi nào và bên trong có gì
joingonka-errorSự cố sau khi mở stream: trường error, sau đó ngắt kết nối không có [DONE].
joingonka-stream-stalledMạ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-unfinishedMạ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-citationsNguồn tìm kiếm web trong delta.annotations — trước khi kết thúc.
joingonka-metaChi 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 đến message_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: tools và tool_choice. Định dạng cũ functions và function_call cũ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 400 sẽ được gateway sửa: role developer thành system, các id lệnh gọi trống hoặc trùng lặp được cấp id duy nhất, arguments dạng object chuyển thành chuỗi JSON, type bị 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ải tool_calls: hãy tăng giới hạn phản hồi.
JSON
{
  "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 $defs và definitions bị xóa; tham chiếu đệ quy trở thành schema không có ràng buộc.
  • pattern chứ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.
  • anyOf và oneOf từ các hằng số được gộp thành enum; 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.

JSON
{
  "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ường reasoning đượ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_effort và reasoning.effort được truyền vào mạng. Nếu model chỉ có hai chế độ, gateway đưa giá trị về chúng: none và 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 (max và 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ó block thinking.

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.

PluginMô tảĐiều kiện
response-healingSử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-sanitizationChe 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-parserTrí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ố.
webTì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ù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 — chunk joingonka-citations trướ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_search thự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}]
}

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ườngMô tả
usage.cost_gnkChi phí yêu cầu tính bằng GNK
usage.platform_fee_gnkTrong đó — phí nền tảng, GNK
usage.total_cost_gnkTổng số tiền trừ, tính bằng GNK
usage.total_cost_usdTổng số tiền tính bằng USD theo tỷ giá GNK hiện tại
  • Trong stream, usage chỉ chứa token; chi phí nằm trong chunk joingonka-meta.
  • Với header x-joingonka-meta: 1, phản hồi POST /v1/chat/completions nhận được block x_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ới 429: cần chờ bấy nhiêu giây trước khi thử lại.
  • Các header X-Title và 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: false trong 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/embeddings trả 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.