> 面向 AI 智能体：配置分步指南 — [`/docs/agents.md`](https://gate.joingonka.ai/docs/agents.md)，文档索引 — [`/llms.txt`](https://gate.joingonka.ai/llms.txt)。

# API 参考

关于网关请求的一切：协议、地址、密钥和参数。下文涵盖流式传输、工具调用、推理、插件以及响应中的请求费用。

## 协议与地址

网关接受 OpenAI 和 Anthropic 格式。OpenAI SDK 的基地址为 `https://gate.joingonka.ai/v1`，Anthropic SDK 为 `https://gate.joingonka.ai`。所有协议共用同一密钥和同一余额：任何格式的请求都走同一条路径。

| 方法与路径 | 格式 | 用途 | 特性 |
| --- | --- | --- | --- |
| `POST /v1/chat/completions` | OpenAI Chat Completions | 聊天、智能体、工具调用 | 主要路径：网关会将其他格式转换为此格式。 |
| `POST /v1/messages` | Anthropic Messages | Claude Code 和 Anthropic SDK | 基地址不含 `/v1`；`claude-*` 模型会被替换为推荐模型；`max_tokens` 字段为必填。 |
| `POST /v1/responses` | OpenAI Responses | Codex CLI 和新的 OpenAI SDK | 无状态：每次请求都需发送完整历史记录。 |
| `POST /v1/completions` | OpenAI Completions (legacy) | 编辑器中的自动补全和代码修改 | `suffix` 作为提示传给模型；响应中包含 `logprobs: null`。 |
| `POST /v1/embeddings` | OpenAI Embeddings | 文本向量表示 | 响应 `501`：网络中暂无嵌入模型。 |

### 发现地址

无需密钥即可访问。带上下文和状态的模型表见 [模型](https://gate.joingonka.ai/zh/docs/models) 章节。

| 方法与路径 | 描述 |
| --- | --- |
| `GET /v1/models` | 模型列表：上下文、价格、支持的参数——字段采用 OpenRouter 格式。 |
| `GET /v1/models/{model}` | 单个模型卡片；id 中的斜杠可用原样或 `%2F`。隐藏或未知模型返回 `404 model_not_found`。 |
| `GET /v1/capabilities` | 网关能力：参数、协议、插件、费用字段和限额（`limits`）。 |
| `GET /v1/plugins` | 插件：id 和名称。 |
| `GET /v1/network-status` | 网络模型状态：可用性、延迟、正常运行时间。 |
| `GET /v1/nodes` | 节点池摘要：总数、活跃数和隔离数。 |
| `GET /v1/web-search/engines` | 网络搜索是否启用及其引擎状态。 |

### Anthropic Messages

- 基地址——`https://gate.joingonka.ai`：SDK 会自动添加 `/v1/messages`。
- 密钥放在 `x-api-key` 请求头中（Anthropic SDK 即如此发送）或 `Authorization: Bearer` 中。
- 网关会将 `claude-*` 模型替换为推荐模型（`MiniMaxAI/MiniMax-M2.7`）；响应中的 `model` 字段保留客户端发送的名称。
- `max_tokens` 为必填，与 Anthropic API 一致；超过模型上限会被截断。
- 流式传输使用 Anthropic 事件；暂停期间网关发送 `event: ping`，故障以 `event: error` 事件形式送达。
- 模型的推理内容不会出现在响应中：没有 `thinking` 块。
- 内置工具 `web_search` 由网关的网络搜索插件执行——参见 [插件](https://gate.joingonka.ai/zh/docs/api#plugins) 章节。
- 不支持 token 计数（`/v1/messages/count_tokens`）——响应 `404`。

用安装器配置 Claude Code 更简单——[接入工具](https://gate.joingonka.ai/zh/docs#connect)。手动配置则使用环境变量；`ANTHROPIC_MODEL` 用于指定网络模型。

#### Claude Code

```bash
export ANTHROPIC_BASE_URL=https://gate.joingonka.ai
export ANTHROPIC_AUTH_TOKEN=$JOINGONKA_API_KEY
export ANTHROPIC_MODEL=MiniMaxAI/MiniMax-M2.7
claude
```

#### cURL

```bash
curl 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

- 网关不存储响应：请在 `input` 中发送完整历史记录。`previous_response_id` 和 `conversation` 字段会返回错误 `400` 及错误码。
- `store` 会被接受但不产生任何影响。
- 工具：`function` 和 `web_search`——后者由网络搜索插件执行。其他内置工具会被网关跳过，请求将在没有它们的情况下执行；通过 `tool_choice` 强制要求此类工具会返回错误 `400`。
- `input_image` 和 `input_file` 部分会返回错误 `400`：网络模型仅处理文本。
- 状态地址（`GET /v1/responses/{id}`, `DELETE /v1/responses/{id}`, `GET /v1/responses/{id}/input_items`, `POST /v1/responses/{id}/cancel`, `POST /v1/responses/compact`）返回 `404` 及错误码——网关不存储响应。
- Codex CLI：在 `model_provider` 中设置你自己的提供商 id（不要用 openai）——这样 Codex 会自行压缩历史记录，无需 `/v1/responses/compact`。

### Legacy Completions

- `prompt` 为字符串或包含单个字符串的数组；响应在 `choices[].text` 中。多个提示词或用 token 代替文本会返回错误 `400`。
- `suffix` 会作为提示词中的提示传给模型：网络并不真正支持中间填充。
- 响应中包含 `logprobs: null`；`best_of` 被忽略；`echo` 可用。

## 密钥与授权

密钥通过 `Authorization: Bearer jg-…` 或 `x-api-key: jg-…` 请求头传递——适用于所有地址。密钥需在 [gate.joingonka.ai/keys](https://gate.joingonka.ai/keys) 页面注册后创建。

| 前缀 | 密钥 | 模型请求 |
| --- | --- | --- |
| `jg-` | 普通账户密钥 | 是 |
| `gc-` | 子密钥：拥有独立限额，费用从所有者余额扣除 | 是 |
| `gm-` | 管理密钥：仅用于管理子密钥 | 否——`403 forbidden` |

- 在控制台中可以为每个密钥设置日、月和总消费限额；超出后返回 `402 child_key_limit_exceeded`。
- 每个密钥每分钟的请求数有限制——具体数值见 [限制](https://gate.joingonka.ai/zh/docs/errors#limits) 章节。
- 只有网站上的演示聊天无需密钥即可使用：从你自己的代码发起的无密钥请求将返回 `402` 及 `is_demo`。
- 密钥只能在控制台中管理：带 API 密钥访问 `/api/keys` 不可用。密钥的余额和消费——[账户 API](https://gate.joingonka.ai/zh/docs/billing#account-api)。

> 密钥属于机密：不要将其保存在代码仓库或前端代码中，请通过环境变量传入。

## 示例

同一个请求在四种 SDK 中的写法。模型使用推荐模型（`MiniMaxAI/MiniMax-M2.7`），密钥来自环境变量 `JOINGONKA_API_KEY`。

### Python

```python
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)
```

### TypeScript

```typescript
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

```bash
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?"}]
  }'
```

### Anthropic SDK

```python
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)
```

### 流式响应

#### Python

```python
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)
```

#### TypeScript

```typescript
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

```bash
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
  }'
```

#### Anthropic SDK

```python
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)
```

## 请求参数

`POST /v1/chat/completions` 中由网关自身保证的参数，列在能力响应的 `supported_parameters` 数组中：

| 参数 | 描述 |
| --- | --- |
| `temperature` | 回答的随机性：值越高，输出越多样。 |
| `top_p` | 按累计概率筛选 token。 |
| `top_k` | 从概率最高的 k 个 token 中筛选。 |
| `min_p` | 相对于概率最高的 token，剔除低概率 token。 |
| `frequency_penalty` | 对频繁重复的惩罚。 |
| `presence_penalty` | 对已出现过的 token 的惩罚。 |
| `repetition_penalty` | 抑制重复的乘数。 |
| `stop` | 生成停止所依据的字符串。 |
| `seed` | 用于复现的随机种子。 |
| `max_tokens` | 回答的 token 上限；超过模型上限的部分会被截断到上限。 |
| `max_completion_tokens` | `max_tokens` 的另一个名称：网关会把值转移到其中。 |
| `tools` | 模型可以调用的函数，采用 OpenAI 格式。 |
| `tool_choice` | 是否调用函数：由模型决定、从不、必须，或指定某一个。 |
| `response_format` | 结构化回答：`json_object` 或 `json_schema`。 |

- 未提供 `temperature` 时，网关会填入 `0.7`。
- 未提供 `max_tokens` 时，网关会填入模型默认值：非流式更短，流式则为模型上限。各模型的具体数值见 [限制](https://gate.joingonka.ai/zh/docs/errors#limits) 一节。

### 原样传给网络

`reasoning_effort`, `reasoning`, `enable_thinking`, `chat_template_kwargs`, `thinking_token_budget`, `min_tokens`, `logit_bias`, `n`, `parallel_tool_calls`, `extra_body`。网关不校验这些参数：值不在网络支持的列表中，会返回类型为 `api_error` 的 `400` 错误。

### 不传给网络

其余字段网关会接收但不传给网络——例如 `user`, `metadata`, `store`, `logprobs`, `top_logprobs`, `thinking`, `stream_options`, `web_search_options`。流式响应中 `usage` 始终会返回。

## 流式传输

- `stream: true` 表示以 SSE 事件形式返回的响应；最后一个事件是 `data: [DONE]`。
- 结束前会先返回一个包含 `usage` 的 chunk——始终如此，即使没有 `stream_options`。
- 在暂停期间，网关每 15 秒发送一条注释 `: keep-alive`——SSE 客户端会忽略它。
- 在流打开之前，失败会以普通响应码返回；流打开之后，则以包含 `joingonka-error` 的 chunk 返回。
- 在 `delta.tool_calls` 中，每个 chunk 只含一个调用：网络粘连在一起的调用，网关会将其拆开。

```text
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]
```

### 网关的服务性 chunk

可通过 `id` 字段识别它们：

| `id` | 何时使用及包含内容 |
| --- | --- |
| `joingonka-error` | 流打开后发生故障：包含 `error` 字段，随后中断且没有 `[DONE]`。 |
| `joingonka-stream-stalled` | 网络沉默时间超过允许的暂停时长：流以 `finish_reason: stop` 关闭。 |
| `joingonka-stream-unfinished` | 网络中断了生成：`finish_reason: length`——请用下一个请求继续。 |
| `joingonka-citations` | 网络搜索的来源在 `delta.annotations` 中——在结束之前返回。 |
| `joingonka-meta` | 费用和耗时——仅在带有 `x-joingonka-meta: 1` 请求头时返回。 |

### 其他协议中的流式传输

- Anthropic Messages：事件从 `message_start` 到 `message_stop`，暂停期间为 `event: ping`，故障为 `event: error`。
- OpenAI Responses：事件为 `response.*`，故障为 `response.failed`。
- Legacy Completions：故障时为 `data: {"error": …}`，然后是 `[DONE]`。

## 工具调用

- OpenAI 格式：`tools` 和 `tool_choice`。旧的 `functions` 和 `function_call` 格式同样受支持——响应也会以该格式返回。
- 在流式中，每个 chunk 只含一个调用：只读取第一个元素的客户端不会丢失调用。
- 网络会以 `400` 错误拒绝的历史记录，网关会进行修复：`developer` 角色变为 `system`，空的和重复的调用 id 会被赋予唯一值，对象形式的 `arguments` 会转换为 JSON 字符串，缺失的 `type` 会被补全，没有名称的调用会连同其结果一起被移除。
- 模型以文本标记形式写出的调用，网关会将其移入 `tool_calls`；在未提供工具的请求响应中出现的虚假调用会被移除。
- 生成在参数中途中断——会返回 `finish_reason: length`，而不是 `tool_calls`：请提高回答上限。

```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"]
      }
    }
  }]
}
```

### JSON-Schema 限制

工具 schema 和 `response_format` 由网络编译为语法；正则表达式使用 RE2 引擎。网关会将 schema 规范化为网络可接受的形式：

- `$ref` 会就地展开，`$defs` 和 `definitions` 部分会被删除；递归引用会变为一个无约束的 schema。
- 含有 RE2 不支持结构（前后瞻、反向引用、原子组、占有量词）的 `pattern` 会被移除；超过 1000 的重复次数会被缩减为 1000。
- 由常量组成的 `anyOf` 和 `oneOf` 会被折叠为 `enum`；如果不可折叠的分支超过 16 个，则整个联合会被移除。

> schema 可能比原始版本更宽松——请在你这一侧校验调用参数。

## 结构化回答

`response_format`：`{"type": "json_object"}` 返回合法 JSON，`{"type": "json_schema", "json_schema": {"name": …, "schema": …}}` 按你的 schema 并受上述限制约束。非流式下被截断的 JSON 会由 `response-healing` 插件修复。

```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"]
      }
    }
  }
}
```

## 推理

- 模型的推理与回答分开返回：`message.reasoning_content`，流式中为 `delta.reasoning_content`。`reasoning` 字段会被网关重命名为该格式。
- 推理会消耗 `max_tokens`：上限过小时，回答会在还没输出文本前就中断（`finish_reason: length`）。
- 如果回答没有文本但有推理，网关会把推理移入 `content`——带工具调用的回答除外。
- `reasoning_effort` 和 `reasoning.effort` 会传给网络。如果模型只有两种模式，网关会把值映射到这两种：`none` 和 `minimal` → `low`，更高的值 → 默认推理。
- 如果节点拒绝了该值，网关会将其降级（`max` 和 `xhigh` → `high`，`minimal` → `low`，否则移除该字段）并重试请求。
- 在 `/v1/messages` 中不传递推理——没有 `thinking` 块。

## 插件

插件通过 `plugins` 字段启用——可以是字符串数组或带选项的对象数组。列表为 `GET /v1/plugins`。

| 插件 | 描述 | 条件 |
| --- | --- | --- |
| `response-healing` | 修复模型回答中被截断的 JSON。 | 仅在非流式且回答以 `{` 或 `[` 开头时生效。 |
| `privacy-sanitization` | 在文本消息中屏蔽邮箱、IPv4、卡号、JWT、64 位十六进制密钥以及形如 `sk-…`, `gw_…`, `gm-…`, `Bearer …` 的密钥。 | 模式由 `privacy_mode` 字段指定：`redact`（默认）或 `tokenize`。 |
| `file-parser` | 从 PDF 中提取文本。 | 当消息文本整体为 base64 编码的 PDF 时：`data:application/pdf;base64,…` 或没有前缀。 |
| `web` | 网络搜索：结果会混入请求，回答会附带来源链接。 | 与 `privacy-sanitization` 同时使用会返回 `400` 错误。 |

### 网络搜索

- 选项：`max_results` —— 从 1 到 10，默认 5；`engine` —— 引擎提示；`search_prompt` —— 结果前的自定义文本；`enabled: false` —— 关闭搜索。
- 来源在 `message.annotations[].url_citation` 中；流式中则在结束前的 `joingonka-citations` chunk 中。
- `mode: "agent"` —— 由模型自行决定是否搜索以及搜索什么；`max_searches` —— 从 1 到 5，默认 3。
- 计费：标准模式下仅计 token（搜索结果计入输入 token）；Agent 模式下按所有步骤的 token 计费，另加每次执行的搜索 1000 nGNK（`x_joingonka.web_search_surcharge_ngonka`）。
- 在 Anthropic Messages 和 OpenAI Responses 中，内置工具 `web_search` 以 Agent 模式运行同一插件。

#### plugins: web

```json
{
  "model": "MiniMaxAI/MiniMax-M2.7",
  "messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
  "plugins": [{"id": "web", "max_results": 5}]
}
```

#### mode: agent

```json
{
  "model": "MiniMaxAI/MiniMax-M2.7",
  "messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
  "plugins": [{"id": "web", "mode": "agent", "max_searches": 3}]
}
```

## 费用与服务字段

非流式响应在 `usage` 中携带请求费用：

| 字段 | 描述 |
| --- | --- |
| `usage.cost_gnk` | 请求费用（GNK） |
| `usage.platform_fee_gnk` | 其中平台加价（GNK） |
| `usage.total_cost_gnk` | 应扣总额（GNK） |
| `usage.total_cost_usd` | 按当前 GNK 汇率折算的美元总额 |

- 在流式响应中，`usage` 只包含 token；费用在 `joingonka-meta` 数据块中。
- 带 `x-joingonka-meta: 1` 请求头时，`POST /v1/chat/completions` 响应会附带 `x_joingonka` 数据块：费用（`cost_ngonka`）、扣费后余额（`balance_ngonka`，仅非流式）以及耗时（`ttft_ms`）。其他协议不返回该数据块。
- `x-request-id` 是请求标识：联系技术支持时请附上它。
- `Retry-After` 随 `429` 返回：需等待这么多秒后再重试。
- `X-Title` 和 `HTTP-Referer` 请求头（与 OpenRouter 相同）可帮助网关识别你的应用；其内容不会被保存。

## 限制

- 图像：`image_url` 部分会被替换为文本占位符——模型看不到图片（能力中的 `vision: false`）。
- 浏览器中仅可从 JoinGonka 域名访问 API（校验 `Origin`）：请从你自己的服务器调用，切勿把密钥放进前端。
- 嵌入：`POST /v1/embeddings` 返回 `501`——网络中暂无嵌入模型。
- 错误码、限流与超时详见 [错误与速率限制](https://gate.joingonka.ai/zh/docs/errors) 章节。
