# Source: https://supanexus.ai/zh/docs/api/endpoints.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL (Global): `https://api.supanexus.ai/v1` | CN: `https://api.supanexus.io/v1` # 接入点 SupaNexus 提供两个接入点,**共用同一套账号与 API Key**。请求路径、鉴权方式、模型列表与计费完全一致,任选其一即可。 其它文档示例中的 `` 请用下表中的基址替换。 ## 基址一览 | 站点 | 基址 | 适用场景 | |------|------|----------| | Global | `https://api.supanexus.ai/v1` | 默认接入点 | | CN | `https://api.supanexus.io/v1` | 备用接入点 | ## 如何选择 - 默认使用 Global。 - 若 Global 不可达或不稳定,改用 CN 备用接入点。 - 切换时只改 `base_url` / `SNX_BASE_URL` / `OPENAI_BASE_URL` 等变量,API Key 与其它代码不变。 ## OpenAI SDK OpenAI 兼容路径需带 `/v1`: ```python from openai import OpenAI client = OpenAI( base_url="https://api.supanexus.ai/v1", # 或 "https://api.supanexus.io/v1" api_key="your-api-key", ) ``` ## Anthropic SDK Anthropic SDK 的 `base_url` **不含** `/v1`: ```python import anthropic client = anthropic.Anthropic( api_key="sk-snx-...", base_url="https://api.supanexus.ai", # 或 "https://api.supanexus.io" ) ``` ## 相关文档 - [快速开始](./quickstart.md) - [OpenAI SDK 集成](./openai-sdk-integration.md) - [Anthropic SDK 集成](./anthropic-sdk-integration.md) --- # Source: https://supanexus.ai/zh/docs/api/quickstart.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 快速开始 两分钟内完成第一次 Chat Completions 调用。 ## 前置条件 1. 可访问 SupaNexus API(基址见 [接入点](./endpoints.md))。 2. 在 [开发者控制台](https://console.supanexus.ai) 创建 **项目 API Key**。 ## 基址 下文示例使用占位符 ``(通常带 `/v1`): ``` /v1 ``` > `` 取值见 [接入点](./endpoints.md)。 将 `deepseek/deepseek-chat` 替换为 `GET /v1/models` 返回的模型 `id`。 ## 发送 Chat Completions ```bash export SNX_API_KEY="your-api-key" export SNX_BASE_URL="/v1" curl -s "${SNX_BASE_URL}/chat/completions" \ -H "Authorization: Bearer ${SNX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek/deepseek-chat", "messages": [{"role": "user", "content": "用一句话说你好。"}] }' ``` ```python from openai import OpenAI client = OpenAI( base_url="/v1", api_key="your-api-key", ) completion = client.chat.completions.create( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "用一句话说你好。"}], ) print(completion.choices[0].message.content) ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ baseURL: "/v1", apiKey: process.env.SNX_API_KEY, }); const completion = await client.chat.completions.create({ model: "deepseek/deepseek-chat", messages: [{ role: "user", content: "用一句话说你好。" }], }); console.log(completion.choices[0]?.message?.content); ``` ```go package main import ( "bytes" "fmt" "io" "net/http" "os" ) func main() { apiKey := os.Getenv("SNX_API_KEY") baseURL := os.Getenv("SNX_BASE_URL") // /v1 body := []byte(`{"model":"deepseek/deepseek-chat","messages":[{"role":"user","content":"用一句话说你好。"}]}`) req, err := http.NewRequest(http.MethodPost, baseURL+"/chat/completions", bytes.NewReader(body)) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+apiKey) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class Quickstart { public static void main(String[] args) throws Exception { String apiKey = System.getenv("SNX_API_KEY"); String baseUrl = System.getenv("SNX_BASE_URL"); // /v1 String json = """ {"model":"deepseek/deepseek-chat","messages":[{"role":"user","content":"用一句话说你好。"}]} """; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(baseUrl + "/chat/completions")) .header("Authorization", "Bearer " + apiKey) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json)) .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```c #include #include #include int main(void) { const char *api_key = getenv("SNX_API_KEY"); const char *base_url = getenv("SNX_BASE_URL"); /* /v1 */ CURL *curl = curl_easy_init(); if (!curl) return 1; char url[512]; snprintf(url, sizeof(url), "%s/chat/completions", base_url); struct curl_slist *headers = NULL; char auth[256]; snprintf(auth, sizeof(auth), "Authorization: Bearer %s", api_key); headers = curl_slist_append(headers, auth); headers = curl_slist_append(headers, "Content-Type: application/json"); const char *payload = "{\"model\":\"deepseek/deepseek-chat\",\"messages\":[{\"role\":\"user\",\"content\":\"用一句话说你好。\"}]}"; curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload); CURLcode res = curl_easy_perform(curl); curl_slist_free_all(headers); curl_easy_cleanup(curl); return res == CURLE_OK ? 0 : 1; } ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ baseURL: process.env.SNX_BASE_URL ?? "/v1", apiKey: process.env.SNX_API_KEY, }); const completion = await client.chat.completions.create({ model: "deepseek/deepseek-chat", messages: [{ role: "user", content: "用一句话说你好。" }], }); console.log(completion.choices[0]?.message?.content); ``` ```ruby require "openai" client = OpenAI::Client.new( access_token: ENV["SNX_API_KEY"], uri_base: ENV.fetch("SNX_BASE_URL", "/v1"), ) response = client.chat( parameters: { model: "deepseek/deepseek-chat", messages: [{ role: "user", content: "用一句话说你好。" }], }, ) puts response.dig("choices", 0, "message", "content") ``` ```php /v1"; $apiKey = getenv("SNX_API_KEY"); $ch = curl_init("{$baseUrl}/chat/completions"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$apiKey}", "Content-Type: application/json", ], CURLOPT_POSTFIELDS => json_encode([ "model" => "deepseek/deepseek-chat", "messages" => [ ["role" => "user", "content" => "用一句话说你好。"], ], ]), ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ```rust use reqwest::blocking::Client; use std::env; fn main() -> Result<(), Box> { let api_key = env::var("SNX_API_KEY")?; let base_url = env::var("SNX_BASE_URL").unwrap_or_else(|_| "/v1".into()); let client = Client::new(); let response = client .post(format!("{base_url}/chat/completions")) .bearer_auth(api_key) .json(&serde_json::json!({ "model": "deepseek/deepseek-chat", "messages": [{"role": "user", "content": "用一句话说你好。"}] })) .send()?; println!("{}", response.text()?); Ok(()) } ``` ```csharp using System.Net.Http.Headers; using System.Text; using System.Text.Json; var apiKey = Environment.GetEnvironmentVariable("SNX_API_KEY"); var baseUrl = Environment.GetEnvironmentVariable("SNX_BASE_URL") ?? "/v1"; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); var body = JsonSerializer.Serialize(new { model = "deepseek/deepseek-chat", messages = new[] { new { role = "user", content = "用一句话说你好。" } }, }); var response = await client.PostAsync( $"{baseUrl}/chat/completions", new StringContent(body, Encoding.UTF8, "application/json")); Console.WriteLine(await response.Content.ReadAsStringAsync()); ``` ```kotlin import java.net.URI import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse fun main() { val apiKey = System.getenv("SNX_API_KEY") val baseUrl = System.getenv("SNX_BASE_URL") ?: "/v1" val json = """ {"model":"deepseek/deepseek-chat","messages":[{"role":"user","content":"用一句话说你好。"}]} """.trimIndent() val request = HttpRequest.newBuilder() .uri(URI.create("$baseUrl/chat/completions")) .header("Authorization", "Bearer $apiKey") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json)) .build() val response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()) println(response.body()) } ``` ```swift import Foundation let apiKey = ProcessInfo.processInfo.environment["SNX_API_KEY"]! let baseURL = ProcessInfo.processInfo.environment["SNX_BASE_URL"] ?? "/v1" var request = URLRequest(url: URL(string: "\(baseURL)/chat/completions")!) request.httpMethod = "POST" request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = """ {"model":"deepseek/deepseek-chat","messages":[{"role":"user","content":"用一句话说你好。"}]} """.data(using: .utf8) let semaphore = DispatchSemaphore(value: 0) URLSession.shared.dataTask(with: request) { data, _, _ in if let data, let text = String(data: data, encoding: .utf8) { print(text) } semaphore.signal() }.resume() semaphore.wait() ``` ```scala import java.net.URI import java.net.http.{HttpClient, HttpRequest, HttpResponse} @main def quickstart(): Unit = val apiKey = sys.env("SNX_API_KEY") val baseUrl = sys.env.getOrElse("SNX_BASE_URL", "/v1") val json = """{"model":"deepseek/deepseek-chat","messages":[{"role":"user","content":"用一句话说你好。"}]}""" val request = HttpRequest.newBuilder() .uri(URI.create(s"$baseUrl/chat/completions")) .header("Authorization", s"Bearer $apiKey") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(json)) .build() val response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()) println(response.body()) ``` ```dart import 'dart:convert'; import 'dart:io'; Future main() async { final apiKey = Platform.environment['SNX_API_KEY']!; final baseUrl = Platform.environment['SNX_BASE_URL'] ?? '/v1'; final client = HttpClient(); final request = await client.postUrl(Uri.parse('$baseUrl/chat/completions')); request.headers.set('Authorization', 'Bearer $apiKey'); request.headers.contentType = ContentType.json; request.write(jsonEncode({ 'model': 'deepseek/deepseek-chat', 'messages': [ {'role': 'user', 'content': '用一句话说你好。'}, ], })); final response = await request.close(); final body = await response.transform(utf8.decoder).join(); print(body); client.close(); } ``` ## 列出可用模型 ```bash curl -s "${SNX_BASE_URL}/models" \ -H "Authorization: Bearer ${SNX_API_KEY}" ``` ```python from openai import OpenAI client = OpenAI( base_url="/v1", api_key="your-api-key", ) models = client.models.list() for model in models.data: print(model.id) ``` ```typescript import OpenAI from "openai"; const client = new OpenAI({ baseURL: process.env.SNX_BASE_URL ?? "/v1", apiKey: process.env.SNX_API_KEY, }); const models = await client.models.list(); for (const model of models.data) { console.log(model.id); } ``` ```javascript import OpenAI from "openai"; const client = new OpenAI({ baseURL: process.env.SNX_BASE_URL ?? "/v1", apiKey: process.env.SNX_API_KEY, }); const models = await client.models.list(); for (const model of models.data) { console.log(model.id); } ``` ```go package main import ( "fmt" "io" "net/http" "os" ) func main() { apiKey := os.Getenv("SNX_API_KEY") baseURL := os.Getenv("SNX_BASE_URL") // /v1 req, err := http.NewRequest(http.MethodGet, baseURL+"/models", nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+apiKey) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() out, _ := io.ReadAll(resp.Body) fmt.Println(string(out)) } ``` ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; public class ListModels { public static void main(String[] args) throws Exception { String apiKey = System.getenv("SNX_API_KEY"); String baseUrl = System.getenv("SNX_BASE_URL"); // /v1 HttpRequest request = HttpRequest.newBuilder() .uri(URI.create(baseUrl + "/models")) .header("Authorization", "Bearer " + apiKey) .GET() .build(); HttpResponse response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```c #include #include #include int main(void) { const char *api_key = getenv("SNX_API_KEY"); const char *base_url = getenv("SNX_BASE_URL"); /* /v1 */ CURL *curl = curl_easy_init(); if (!curl) return 1; char url[512]; snprintf(url, sizeof(url), "%s/models", base_url); struct curl_slist *headers = NULL; char auth[256]; snprintf(auth, sizeof(auth), "Authorization: Bearer %s", api_key); headers = curl_slist_append(headers, auth); curl_easy_setopt(curl, CURLOPT_URL, url); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); CURLcode res = curl_easy_perform(curl); curl_slist_free_all(headers); curl_easy_cleanup(curl); return res == CURLE_OK ? 0 : 1; } ``` ```ruby require "openai" client = OpenAI::Client.new( access_token: ENV["SNX_API_KEY"], uri_base: ENV.fetch("SNX_BASE_URL", "/v1"), ) response = client.models.list response["data"].each { |model| puts model["id"] } ``` ```php /v1"; $apiKey = getenv("SNX_API_KEY"); $ch = curl_init("{$baseUrl}/models"); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ "Authorization: Bearer {$apiKey}", ], ]); $response = curl_exec($ch); curl_close($ch); echo $response; ``` ```rust use reqwest::blocking::Client; use std::env; fn main() -> Result<(), Box> { let api_key = env::var("SNX_API_KEY")?; let base_url = env::var("SNX_BASE_URL").unwrap_or_else(|_| "/v1".into()); let client = Client::new(); let response = client .get(format!("{base_url}/models")) .bearer_auth(api_key) .send()?; println!("{}", response.text()?); Ok(()) } ``` ```csharp using System.Net.Http.Headers; var apiKey = Environment.GetEnvironmentVariable("SNX_API_KEY"); var baseUrl = Environment.GetEnvironmentVariable("SNX_BASE_URL") ?? "/v1"; using var client = new HttpClient(); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); var response = await client.GetAsync($"{baseUrl}/models"); Console.WriteLine(await response.Content.ReadAsStringAsync()); ``` ```kotlin import java.net.URI import java.net.http.HttpClient import java.net.http.HttpRequest import java.net.http.HttpResponse fun main() { val apiKey = System.getenv("SNX_API_KEY") val baseUrl = System.getenv("SNX_BASE_URL") ?: "/v1" val request = HttpRequest.newBuilder() .uri(URI.create("$baseUrl/models")) .header("Authorization", "Bearer $apiKey") .GET() .build() val response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()) println(response.body()) } ``` ```swift import Foundation let apiKey = ProcessInfo.processInfo.environment["SNX_API_KEY"]! let baseURL = ProcessInfo.processInfo.environment["SNX_BASE_URL"] ?? "/v1" var request = URLRequest(url: URL(string: "\(baseURL)/models")!) request.httpMethod = "GET" request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization") let semaphore = DispatchSemaphore(value: 0) URLSession.shared.dataTask(with: request) { data, _, _ in if let data, let text = String(data: data, encoding: .utf8) { print(text) } semaphore.signal() }.resume() semaphore.wait() ``` ```scala import java.net.URI import java.net.http.{HttpClient, HttpRequest, HttpResponse} @main def listModels(): Unit = val apiKey = sys.env("SNX_API_KEY") val baseUrl = sys.env.getOrElse("SNX_BASE_URL", "/v1") val request = HttpRequest.newBuilder() .uri(URI.create(s"$baseUrl/models")) .header("Authorization", s"Bearer $apiKey") .GET() .build() val response = HttpClient.newHttpClient() .send(request, HttpResponse.BodyHandlers.ofString()) println(response.body()) ``` ```dart import 'dart:convert'; import 'dart:io'; Future main() async { final apiKey = Platform.environment['SNX_API_KEY']!; final baseUrl = Platform.environment['SNX_BASE_URL'] ?? '/v1'; final client = HttpClient(); final request = await client.getUrl(Uri.parse('$baseUrl/models')); request.headers.set('Authorization', 'Bearer $apiKey'); final response = await request.close(); final body = await response.transform(utf8.decoder).join(); print(body); client.close(); } ``` ## 下一步 - [认证](./authentication.md) — API Key 格式与错误 - [Chat Completions](./chat-completions.md) — 完整请求/响应说明 - [OpenAI SDK 集成](./openai-sdk-integration.md) — 无缝迁移指南 --- # Source: https://supanexus.ai/zh/docs/api/authentication.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 认证 SupaNexus 使用 **Bearer API Key** 认证,与 OpenAI 客户端库兼容。 ## 请求头格式 ```http Authorization: Bearer ``` 在 `Authorization` 请求头中携带 API Key 密钥。SupaNexus 会在每次请求时校验 Key 是否有效。 ## 创建 API Key 1. 登录 [开发者控制台](https://console.supanexus.ai)。 2. 进入组织 → 项目 → **API Keys**。 3. 创建 Key 并立即复制密钥(仅显示一次)。 每个 Key 绑定 **项目** 与 **组织**,用量计入该项目。 ## 过期 若 Key 设置了过期时间且已过期,返回 **401**: ```json { "error": { "code": 401, "message": "Invalid credentials. Provide a valid API key in the Authorization header." } } ``` ## 缺失或无效 Key | 情况 | HTTP | 响应体 | |------|------|--------| | 无 `Authorization` 头 | 401 | `{"error":{"code":401,"message":"..."}}` | | Key 错误或已销毁 | 401 | 同上 | | 服务暂时不可用 | 503 | `{"error":{"code":503,"message":"..."}}` | ## 账号封禁校验 API Key 校验通过后,SupaNexus 还会检查该 Key 所属**组织归属用户**的平台账号状态: | 账号状态 | 控制台登录 | API `/v1/*` | |----------|------------|-------------| | 正常 | 允许 | 允许 | | 已封禁 | 拒绝 | **403**,见下文 | 封禁由平台管理员执行;解封后控制台与 API 均可恢复正常使用。**封禁不会自动销毁 API Key**,但 API 会在每次请求时拦截。 ```json { "error": { "code": 403, "message": "Your account has been suspended. Contact support for assistance." } } ``` 收到该错误时请勿重试;联系平台客服或管理员处理账号状态。 ## 认证不包含的内容 - **IP 限流** 对 `/v1/*` 同样返回 OpenRouter 格式 429 — 见 [限流与配额](./rate-limits-and-quotas.md)。 - **配额与余额检查** 可能在认证之后、对 `POST /v1/chat/completions` 与 `POST /v1/messages` 生效,具体取决于部署配置。 ## 安全建议 - 将 Key 存放在环境变量或密钥管理系统中,勿写入代码仓库。 - 定期轮换 Key,在控制台销毁不用的 Key。 - 开发/预发/生产环境使用不同 Key。 --- # Source: https://supanexus.ai/zh/docs/api/chat-completions.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Chat Completions 为多轮对话创建模型回复。 ``` POST /v1/chat/completions ``` > **协议说明**:本接口是 OpenAI **形态**入口,可调用目录中任意可售卖模型。客户端形态与上游协议可不一致,由网关转换(如调 `anthropic/*` 时转 Anthropic Messages)。发图到 Claude 请用 [`/v1/messages`](./messages.md)。 ## 认证 必需:`Authorization: Bearer ` ## 请求头 | 头 | 必需 | 说明 | |----|------|------| | `Authorization` | 是 | Bearer API Key | | `Content-Type` | 是 | `application/json` | | `Idempotency-Key` | 否 | 24 小时内防止重复调用 | | `Accept-Language` / `X-Locale` | 否 | 影响部分错误的本地化文案 | ## 请求体 SupaNexus 接受 **OpenAI Chat Completions** JSON 格式,识别 `model` 与 `stream`;其余字段按 OpenAI 兼容方式处理。多模态(图片 `image_url`、视频 `video_url` 仅公网 URL)见 [参数 → 多模态输入](./parameters.md)。 ```json { "model": "deepseek/deepseek-chat", "messages": [ {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Hello!"} ], "stream": false, "temperature": 0.7, "max_tokens": 1024 } ``` | 字段 | 必需 | 说明 | |------|------|------| | `model` | 是 | `GET /v1/models` 返回的模型 id(如 `deepseek/deepseek-chat`) | | `messages` | 是 | OpenAI 格式消息数组 | | `stream` | 否 | `true` 启用 SSE 流式 — 见 [流式响应](./streaming.md) | ## 非流式响应 返回 OpenAI 兼容 JSON。示例: ```json { "id": "chatcmpl-...", "object": "chat.completion", "choices": [ { "index": 0, "message": {"role": "assistant", "content": "Hello! How can I help?"}, "finish_reason": "stop" } ], "usage": { "prompt_tokens": 2000, "completion_tokens": 300, "total_tokens": 2300, "prompt_tokens_details": { "cached_tokens": 1500 } } } ``` `prompt_tokens_details.cached_tokens`(OpenAI)表示 **命中 Prompt Cache** 的输入 token 数。SupaNexus 据此与平台配置的 [缓存输入单价](/help/prompt-cache-pricing) 计费;未配置分档时仍按全部输入 token 计 **输入价**。 ## 用量与 Prompt Cache 计费 SupaNexus **不运行** Prompt Cache,但会 **读取** 响应 `usage` 中的缓存字段并计入账单: | 服务商 | 典型字段 | |------|----------| | OpenAI | `usage.prompt_tokens_details.cached_tokens` | | Anthropic | `usage.cache_read_input_tokens` | 计费(简化): ``` 费用 ≈ (prompt_tokens − cached_hit) × 输入单价 + cached_hit × 缓存输入单价 + completion_tokens × 输出单价 ``` 价目表以 [模型广场](https://console.supanexus.ai/models) 为准,详见 [模型定价](./model-pricing.md)。服务端用量明细可含 `cached_input_tokens`。 ## 响应头(SupaNexus) | 头 | 说明 | |----|------| | `X-SNX-Trace-ID` | 唯一请求 ID,联系支持时可提供 | | `X-SNX-Model` | 本次请求使用的模型 id | | `X-SNX-Provider` | 实际提供推理的服务商标识 | ## 幂等 发送 `Idempotency-Key: <唯一字符串>` 可在 **24 小时** 内按 API Key 去重。若 Key 已处理过: - **HTTP 409** - `error.code`: `duplicate_request` 未提供 `Idempotency-Key` 时,可能回退使用 `X-SNX-Trace-ID`。 ## 路由 SupaNexus 根据你请求的模型 id 选择可用服务。若暂时无法完成请求,可能返回 **502** 或 **503**。 ## 数据与隐私 SupaNexus **不保存跨请求的对话历史**:每次请求由调用方自行拼装 `messages[]`。 | 处理方式 | 说明 | |----------|------| | 请求体 | SupaNexus 默认**不持久化** prompt/completion 正文 | | 用量记录 | 调用时间、模型、Token 数量等计费所需信息 | | 排障 | 联系支持时可提供 `X-SNX-Trace-ID` | 开发者控制台**文本对话**体验窗中的聊天记录仅保存在**当前浏览器会话**;刷新或关闭页面后不会从 SupaNexus 服务端恢复。 详见 [隐私政策](/privacy) 与 [服务条款](/terms)。 ## 常见错误 | HTTP | 说明 | |------|------| | 400 | 缺少 `model`、JSON 无效;非法 `video_url`(非公网 http(s)) | | 401 | 认证失败 | | 413 | 请求体超过默认 **64 MB** | | 402 | 账户余额不足(`error.code=402`) | | 404 | 未知或不可用模型 | | 408 | 请求超时(默认 120s) | | 409 | 幂等冲突 | | 429 | 用量配额已用尽 | | 502 | 服务暂时不可用 | | 503 | 服务暂时不可用 | 完整说明见 [错误处理](./errors.md)。 ## 相关 - [参数](./parameters.md) - [流式响应](./streaming.md) - [Messages(Anthropic)](./messages.md) - [模型定价](./model-pricing.md) - [响应头](./response-headers.md) --- # Source: https://supanexus.ai/zh/docs/api/messages.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Messages(Anthropic 兼容) 使用 **Anthropic Messages API** 格式创建模型回复,与 [OpenRouter `/v1/messages`](https://openrouter.ai/docs/api/api-reference/anthropic-messages/create-messages) 类似。 ``` POST /v1/messages ``` 适用于 **Anthropic SDK**、**Claude Code** 等期望原生 Anthropic 请求/响应形态的客户端。也可调用非 Anthropic 上游模型(网关转 OpenAI Chat Completions)。发图到 Claude 请用本接口。 ## 认证 必需:`Authorization: Bearer `(与 `/v1/chat/completions` 使用同一 SupaNexus API Key)。 ## 请求头 | 头 | 必需 | 说明 | |----|------|------| | `Authorization` | 是 | Bearer API Key | | `Content-Type` | 是 | `application/json` | | `Idempotency-Key` | 否 | 24 小时内按 Key 去重 | | `Accept-Language` / `X-Locale` | 否 | 部分错误文案本地化 | ## 请求体 SupaNexus 接受标准 Anthropic Messages JSON,识别 `model` 与 `stream` 参数。 ```json { "model": "anthropic/claude-3-5-sonnet", "max_tokens": 1024, "messages": [ {"role": "user", "content": "你好!"} ], "stream": false } ``` | 字段 | 必需 | 说明 | |------|------|------| | `model` | 是 | `GET /v1/models` 返回的模型 id | | `messages` | 是 | Anthropic 消息数组 | | `max_tokens` | 是 | 最大输出 token(Anthropic 必填) | | `system` | 否 | 系统提示(字符串或 content blocks) | | `stream` | 否 | `true` 时返回 Anthropic SSE 事件流 | | `temperature`、`top_p`、`stop_sequences` | 否 | 支持时透传 | | `tools`、`tool_choice`、`thinking`、`metadata` | 否 | 按 Anthropic 兼容方式透传(如模型支持) | ## 多模态输入(图片) 当模型 `architecture.input_modalities` 包含 `"image"` 时,`messages[].content` 可为 **content block 数组**,同时携带文本与图片。 ### Base64 图片示例 ```json { "model": "anthropic/claude-sonnet-5", "max_tokens": 1024, "messages": [ { "role": "user", "content": [ { "type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": "/9j/4AAQSkZJRg..." } }, {"type": "text", "text": "请描述这张图片"} ] } ] } ``` ### URL 图片示例 ```json { "type": "image", "source": { "type": "url", "url": "https://example.com/photo.jpg" } } ``` ### 限制:OpenAI 协议上游模型 若目标模型的上游为 **OpenAI Chat Completions** 协议(非 `anthropic/*`),Anthropic image block **不会**被转换成 `image_url`,上游通常会拒绝请求。此时请改用 [`POST /v1/chat/completions`](./chat-completions.md) 与 OpenAI `image_url` 格式,详见 [参数 → 多模态输入](./parameters.md)。 **建议**:要发图片时,客户端协议须与模型上游协议一致——`anthropic/*` 用本端点,其余模型用 `/v1/chat/completions`。 ## 非流式响应 Anthropic 形态 JSON: ```json { "id": "msg_...", "type": "message", "role": "assistant", "model": "claude-3-5-sonnet-20241022", "content": [{"type": "text", "text": "你好!有什么可以帮你的?"}], "stop_reason": "end_turn", "usage": {"input_tokens": 12, "output_tokens": 8} } ``` ## 流式 `stream: true` 时返回 Anthropic 事件流(`message_start`、`content_block_delta`、`message_delta`、`message_stop`)。通用 SSE 说明见 [流式响应](./streaming.md)。 ## 响应头(SupaNexus) 与 Chat Completions 相同:`X-SNX-Trace-ID`、`X-SNX-Model`、`X-SNX-Provider`。 ## 错误格式 `/v1/messages` 返回 **Anthropic 形态**错误(非 OpenRouter 数字 `error.code`): ```json { "type": "error", "error": { "type": "invalid_request_error", "message": "you must provide a model parameter" } } ``` | HTTP | 典型 `error.type` | |------|-------------------| | 400 | `invalid_request_error` | | 401 | `authentication_error` | | 402 | `billing_error` | | 404 | `not_found_error` | | 429 | `rate_limit_error` | | 503 | `overloaded_error` | 若需要 OpenRouter 形态错误体,请使用 [`POST /v1/chat/completions`](./chat-completions.md)。 ## OpenAI 与 Anthropic 端点对照 | 客户端 | 端点 | 错误体 | |--------|------|--------| | OpenAI SDK | `POST /v1/chat/completions` | OpenRouter `{error:{code,message}}` | | Anthropic SDK / Claude Code | `POST /v1/messages` | Anthropic `{type,error:{type,message}}` | 两者共用 **同一 SupaNexus API Key**,路由、配额与计费逻辑一致。 ## 相关 - [Anthropic SDK 集成](./anthropic-sdk-integration.md) - [Chat Completions](./chat-completions.md) - [认证](./authentication.md) - [错误处理](./errors.md) --- # Source: https://supanexus.ai/zh/docs/api/models.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 模型 列出并查询 API Key 可用的模型。 ## 列出模型 ``` GET /v1/models ``` ### 查询参数 | 参数 | 类型 | 默认 | 说明 | |------|------|------|------| | `limit` | integer | 500 | 最大条数(1–1000) | ### 响应 ```json { "object": "list", "data": [ { "id": "deepseek/deepseek-chat", "object": "model", "name": "DeepSeek Chat", "context_length": 128000, "architecture": { "input_modalities": ["text"], "output_modalities": ["text"] }, "supported_parameters": ["temperature", "max_tokens", "top_p"], "default_parameters": {"temperature": 0.7} } ] } ``` 仅返回 **对你的 API Key 可用** 的模型,不可用或已下线的模型不会出现在列表中。 ## 获取单个模型 ``` GET /v1/models/{id} ``` `{id}` 路径段支持斜杠(如 `deepseek/deepseek-chat`)。 ### 响应 与列表 `data` 中单条对象相同。 ### 错误 | HTTP | `error.code` | 原因 | |------|--------------|------| | 400 | — | 缺少 model id | | 404 | `model_not_found` | 未知或不可用 | | 502 | — | 模型列表暂时不可用 | ## 模型 id 格式 调用 Chat Completions 时,`model` 参数请使用 `GET /v1/models` 返回的 **`id`**(通常为 `{厂商}/{模型名}` 格式,例如 `deepseek/deepseek-chat`)。 **售价(输入 / 缓存输入 / 输出)** 不在本接口返回;请在 [开发者控制台 → 模型广场](https://console.supanexus.ai/models) 查看,详见 [模型定价](./model-pricing.md)。 ## 响应字段说明 相比最小 OpenAI 模型对象,列表与详情可能包含以下附加信息: | 字段 | 说明 | |------|------| | `name` | 展示名称 | | `context_length` | 最大上下文长度 | | `architecture` | 输入/输出模态(`input_modalities` / `output_modalities`;常见取值:`text`、`image`、`video`) | | `supported_parameters` | 模型支持的参数 | | `default_parameters` | 建议默认值 | 发图片或视频前,检查目标模型的 `architecture.input_modalities` 是否包含 `"image"` / `"video"`。 | 上游类型 | 推荐端点 | 请求格式 | |----------|----------|----------| | 非 Anthropic(OpenAI 兼容上游) | [`POST /v1/chat/completions`](./chat-completions.md) | `image_url`(URL 或 data URI);`video_url`(**仅公网 http(s)**)— 见 [参数 → 多模态输入](./parameters.md) | | `anthropic/*`(Anthropic Messages 上游) | [`POST /v1/messages`](./messages.md) | Anthropic image content blocks — 见 [Messages → 多模态输入](./messages.md)(视频不走此路径) | 跨协议发图(例如用 Chat Completions 调 Anthropic 模型,或用 Messages 调 OpenAI 上游模型)当前**不可靠**:图片可能被静默丢弃或被上游拒绝。请按上表选择端点。Whale **不支持** 将视频以 data URI 传入网关。 ## 相关 - [Chat Completions](./chat-completions.md) - [模型定价](./model-pricing.md) - [参数](./parameters.md) --- # Source: https://supanexus.ai/zh/docs/api/model-pricing.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 模型定价 SupaNexus 按 **Token 用量**计费。OpenAPI `GET /v1/models` 仅返回模型元数据,**不含售价**;请以**开发者控制台 → 模型广场**为准查看价格。 ## 在哪里查看价格 1. 登录 [开发者控制台](https://console.supanexus.ai)。 2. 打开 **[模型广场](https://console.supanexus.ai/models)**。 3. 进入目标模型的详情页,查看 **定价信息**。 若运营已为模型配置分档,详情页通常显示: | 档位 | 含义 | |------|------| | **输入** | 未命中缓存的新增输入 token | | **缓存输入** | 命中 Prompt Cache 的输入 token(通常更便宜) | | **输出** | 模型生成的 completion token | 部分模型可能暂未公开售价;以模型广场实际展示为准。 ## OpenAPI 与扣费 | 场景 | 说明 | |------|------| | 查模型列表 | `GET /v1/models` — 不含价格 | | 实际扣费 | `POST /v1/chat/completions` 或 `POST /v1/messages` 成功后,按响应中的 token 用量(含缓存命中)与模型广场所示单价计费 | 计费公式(简化)见 [Chat Completions — 用量与 Prompt Cache 计费](./chat-completions.md#用量与-prompt-cache-计费)。 ## 相关 - [模型](./models.md) — OpenAPI `GET /v1/models` - [帮助:计费与余额](/help/billing) - [帮助:缓存输入与 Prompt Cache 定价](/help/prompt-cache-pricing) --- # Source: https://supanexus.ai/zh/docs/api/streaming.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 流式响应 使用 **Server-Sent Events (SSE)** 流式返回 Chat Completions token。 ## 启用流式 在请求体中设置 `"stream": true`: ```json { "model": "deepseek/deepseek-chat", "messages": [{"role": "user", "content": "数到五。"}], "stream": true } ``` **思考型 / 长推理模型请务必使用 `stream: true`。** 非流式请求在 CDN(如 Cloudflare)后可能受约 100s 首字节限制而中断。流式路径下网关会周期性发送 SSE 注释行(`: keepalive`),各语言 SDK 会忽略注释,不影响解析。 ## 响应格式 - **Content-Type**:`text/event-stream` - 每行:`data: ` - 结束:`data: [DONE]` 示例(`data:` 后 JSON 实际传输多为单行,此处换行便于阅读): ```http data: { "id": "chatcmpl-...", "object": "chat.completion.chunk", "choices": [ { "index": 0, "delta": { "content": "一" }, "finish_reason": null } ] } data: { "id": "chatcmpl-...", "object": "chat.completion.chunk", "choices": [ { "index": 0, "delta": { "content": "、二" }, "finish_reason": null } ] } data: [DONE] ``` ## 流式 usage 流式响应末尾可能包含 `usage` 对象(取决于模型支持情况)。 ## curl 示例 ```bash curl -N "${SNX_BASE_URL}/chat/completions" \ -H "Authorization: Bearer ${SNX_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "model": "deepseek/deepseek-chat", "stream": true, "messages": [{"role": "user", "content": "打个招呼"}] }' ``` 使用 `-N` 禁用 curl 缓冲。 ## OpenAI SDK(Python) ```python stream = client.chat.completions.create( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "打个招呼"}], stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ## 错误处理 | 阶段 | 行为 | |------|------| | **流开始前** | HTTP 4xx/5xx + JSON `error`(与非流式相同) | | **流进行中** | 客户端应处理 SSE 截断 | 配额、余额、认证错误通常在**首字节之前**返回。 ## 相关 - [Chat Completions](./chat-completions.md) - [错误处理](./errors.md) --- # Source: https://supanexus.ai/zh/docs/api/parameters.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 参数 `POST /v1/chat/completions` 请求参数说明。 ## 必需 | 参数 | 类型 | 说明 | |------|------|------| | `model` | string | `GET /v1/models` 中的模型 id | | `messages` | array | OpenAI 聊天消息;`content` 可为字符串,也可为 content part 数组(文本 + 图片 / 视频等) | ## 常用可选参数 SupaNexus 在模型支持范围内 **透传** OpenAI 标准参数。可用性取决于模型 — 见模型对象的 `supported_parameters`。 | 参数 | 类型 | 说明 | 示例 | |------|------|------|------| | `stream` | boolean | 是否**逐字流式**返回;聊天界面通常设为 `true`,批处理可设为 `false` | `"stream": true` | | `temperature` | number | **随机程度**:越高越发散、越有创意;越低越稳定、越可重复。日常对话常用 `0.7`,事实问答可降到 `0`–`0.3` | `"temperature": 0.7` | | `top_p` | number | 另一种控制随机性的方式(核采样),一般**与 temperature 二选一**微调即可 | `"top_p": 0.9` | | `max_tokens` | integer | **回复长度上限**(token 数),防止一次生成过长或超出预算 | `"max_tokens": 1024` | | `frequency_penalty` | number | **少重复同一用词**:越高越不爱「车轱辘话」 | `"frequency_penalty": 0.5` | | `presence_penalty` | number | **鼓励聊新内容**:越高越不容易一直卡在同一个话题上 | `"presence_penalty": 0.3` | | `stop` | string 或 array | 模型生成到这些**停止词**时结束;可用来截断列表、段落等 | `"stop": ["\n\n", "END"]` | | `tools` | array | 告诉模型**可以调用哪些函数**(如查天气、查订单);需模型支持 Function Calling | 见下方示例 | | `tool_choice` | string 或 object | 是否必须调工具:`"auto"` 由模型决定,`"none"` 禁止,`"required"` 必须调 | `"tool_choice": "auto"` | | `response_format` | object | 要求模型按**指定格式**输出,例如只要合法 JSON | `"response_format": {"type": "json_object"}` | | `user` | string | **终端用户 id**(你的 App 里每个用户的标识),便于滥用追踪;OpenAI 模型还可提高 Prompt Cache 命中率 | `"user": "user-42"` | `tools` 示例(简化): ```json "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "查询指定城市的当前天气", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "城市名,如 上海" } }, "required": ["city"] } } } ] ``` ## 多模态输入 当模型支持视觉或视频时,`messages[].content` 可为 **content part 数组**(OpenAI 兼容格式)。 先通过 `GET /v1/models` 确认 `architecture.input_modalities`:含 `"image"` 可发图,含 `"video"` 可发视频。纯文本模型(仅 `["text"]`)不接受媒体。 ### 图片(`image_url`) #### URL 图片示例 ```json { "model": "google/gemini-2.5-flash", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "请描述这张图片的内容"}, { "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } } ] } ] } ``` #### Base64 图片示例 将 `image_url.url` 设为 data URI: ```json { "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..." } } ``` Base64 会使请求体体积膨胀约 **33%**。默认请求体上限为 **64 MB**,超限返回 **413**(`error.code` = `request_too_large`)。大图建议使用公网可访问的 URL。 ### 视频(`video_url`) 当 `input_modalities` 包含 `"video"`(例如 `minimax/minimax-m3`、`moonshot/kimi-k2.6`)时,可使用 `video_url` content part。 **Whale 第一版约定**: | 允许 | 不允许 | |------|--------| | 公网 `http://` / `https://` 视频 URL(上游自行拉取) | `data:`(base64)、`file://`、`blob:`、厂商私有引用(如 `mm_file://`、`ms://`) | 非法 `video_url` 网关返回 **400**,不会转发到上游。视频勿用 data URI 过网关,以免占用平台带宽。 #### 公网视频 URL 示例 ```json { "model": "minimax/minimax-m3", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "总结这个视频的主要内容"}, { "type": "video_url", "video_url": { "url": "https://example.com/demo.mp4", "detail": "default" } } ] } ] } ``` 部分上游还支持 `fps` 等抽帧字段,在模型支持范围内会透传。 ### 限制:Anthropic 上游模型 用 OpenAI 客户端(`POST /v1/chat/completions`)调用 **`anthropic/*`** 时,网关会做协议转换并将消息压成纯文本,**图片会被静默丢弃且不报错**。发图请用 [`POST /v1/messages`](./messages.md)。 **建议**:发图时客户端协议与上游一致——`anthropic/*` 用 `/v1/messages`,其余用 `/v1/chat/completions`。 ## 请求处理说明 ### 识别的字段 - `model` — 本次调用的模型 id - `stream` — 是否返回 SSE 流式响应 ### 流式 usage `stream: true` 时,响应末尾可能包含 `usage` 对象(取决于模型支持情况)。 ### 其它参数 请求体中其余 JSON 字段在体积限制内按 OpenAI 兼容方式处理。 ## 请求体大小限制 默认最大 **64 MB**(`GATEWAY_OPENAPI_MAX_REQUEST_BODY_BYTES`)。 超限返回 **413**,`error.code` 为 `request_too_large`。大图可用 data URI;**大视频必须用公网 URL**,不要把视频 base64 塞进请求体。 ## 模型默认参数 `GET /v1/models` 中的 `default_parameters` 为建议默认值,客户端可在请求中覆盖。 ## 相关 - [模型](./models.md) - [Chat Completions](./chat-completions.md) - [Messages(Anthropic)](./messages.md) - [错误](./errors.md) --- # Source: https://supanexus.ai/zh/docs/api/errors.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 错误处理 SupaNexus API(`/v1/*`)错误响应采用 **[OpenRouter 兼容格式](https://openrouter.ai/docs/api/reference/errors-and-debugging)**:`error.code` 为 **数字**,与 HTTP 状态码一致。 ## 错误 JSON 格式 ```json { "error": { "code": 402, "message": "Your account or API key has insufficient credits. Add more credits and retry the request.", "metadata": {} } } ``` | 字段 | 说明 | |------|------| | `error.code` | **整数**,等于 HTTP 响应 status | | `error.message` | 人类可读描述 | | `error.metadata` | 可选扩展(如 provider 错误详情) | ## HTTP 状态码参考 | HTTP | 场景 | |------|------| | 400 | 参数无效、JSON 解析失败;`video_url` 非公网 http(s)(含 data URI / file / 厂商私有 scheme) | | 401 | API Key 缺失、错误或过期 | | 413 | 请求体超过上限(默认 **64 MB**,`error.code` = `request_too_large`) | | 402 | 账户/API Key 余额不足 | | 403 | 账号已封禁,或权限不足 / 缺少组织/项目上下文 | | 404 | 模型不存在或不可售卖 | | 408 | 请求超时 | | 409 | 幂等 Key 重复使用 | | 429 | 速率或用量配额超限(可能有 `Retry-After`) | | 501 | Embeddings / Images 尚未实现 | | 502 | 服务暂时不可用 | | 503 | 服务暂时不可用 | | 500 | 服务内部错误 | ## 账号封禁(403) 平台用户被管理员封禁后,所有 `/v1/*` 请求在 API Key 校验通过后返回: ```json { "error": { "code": 403, "message": "Your account has been suspended. Contact support for assistance." } } ``` - 与 Key 是否有效无关(Key 未销毁时仍可能返回此错误) - 解封后立即恢复,无需重新创建 Key - 详见 [认证 — 账号封禁校验](./authentication.md#账号封禁校验) ## 重试建议 | HTTP | 是否重试 | 说明 | |------|----------|------| | 401 | 否 | 修正 API Key | | 403 | 否 | 账号封禁时联系管理员;其它 403 检查权限与上下文 | | 402 | 否 | 充值或联系平台管理员 | | 404 | 否 | 使用有效 model id | | 408 | 视情况 | 缩短 payload 或增加客户端超时 | | 409 | 否 | 使用新的 Idempotency-Key | | 429 | 是 | 遵守 `Retry-After` | | 502 | 视情况 | 指数退避后重试 | | 503 | 视情况 | 短间隔退避 | ## 服务认证失败 推理服务认证失败时,SupaNexus 通常返回 **502**,消息为 `"Upstream authentication failed."`,不暴露服务商细节。 ## Anthropic `/v1/messages` 错误 `POST /v1/messages` 返回 **Anthropic 形态** JSON,而非 OpenRouter 数字 code: ```json { "type": "error", "error": {"type": "authentication_error", "message": "Invalid API key"} } ``` 详见 [Messages](./messages.md)。Chat Completions 仍使用上文 OpenRouter 格式。 ## 流式错误 **流开始前**的错误使用上述 JSON 格式与对应 HTTP 状态码。见 [流式响应](./streaming.md)。 ## 相关 - [限流与配额](./rate-limits-and-quotas.md) - [认证](./authentication.md) --- # Source: https://supanexus.ai/zh/docs/api/rate-limits-and-quotas.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 限流与配额 SupaNexus 可能应用多层独立限制。具体阈值取决于你的部署环境 — 请咨询平台管理员或查看开发者控制台。 ## 1. IP 限流 作用于 **所有路由**(含未携带有效 API Key 的请求),按客户端 IP 计量。 常见默认值:约 **120 次/分钟/IP**(启用时)。 超限时: - **HTTP 429** - OpenRouter 格式(`/v1/*` 与其它路由一致): ```json { "error": { "code": 429, "message": "You are being rate limited." } } ``` 响应可能包含 **`Retry-After`** 头(秒)。 > **说明:** 该限制按 **IP 地址** 计算,非按 API Key。 ## 2. 用量配额(可选) 若为你的组织或项目配置了配额,可能仅对 `POST /v1/chat/completions` 生效。 超限时: - **HTTP 429** - `error.code`: **429**(数字) - 可能设置 **`Retry-After`** 头(秒) ## 3. 账户余额(可选) 若启用了预付费或余额检查,可能仅对 `POST /v1/chat/completions` 生效。 | HTTP | 含义 | |------|------| | 402 | 本账期额度不足(`error.code=402`) | | 403 | 缺少组织上下文 | **402 vs 429:** 余额不足返回 **402 Payment Required**;配额或花费上限返回 **429 Too Many Requests**。 ## 对比表 | 层级 | 典型范围 | 错误格式 | HTTP | |------|----------|----------|------| | IP 限流 | 全路由 | OpenRouter `{error:{code,message}}` | 429 | | 用量配额 | 仅 Chat | OpenRouter | 429 | | 账户余额 | 仅 Chat | OpenRouter | 402 | ## 最佳实践 - 对 429 做指数退避,遵守 `Retry-After`。 - 不同应用使用不同 API Key,便于在控制台区分用量。 - 在开发者控制台监控用量,避免触顶。 ## 相关 - [错误处理](./errors.md) - [Chat Completions](./chat-completions.md) --- # Source: https://supanexus.ai/zh/docs/api/response-headers.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # 响应头 SupaNexus 在 API 响应中添加诊断头。 ## 全局头 | 头 | 出现位置 | 说明 | |----|----------|------| | `X-SNX-Trace-ID` | 所有响应 | 本请求唯一 ID;联系支持时请提供 | ## Chat Completions 头 | 头 | 出现位置 | 说明 | |----|----------|------| | `X-SNX-Model` | `POST /v1/chat/completions` | 请求的逻辑模型 id | | `X-SNX-Provider` | `POST /v1/chat/completions` | 实际提供推理的服务商标识 | 示例: ```http HTTP/1.1 200 OK Content-Type: application/json X-SNX-Trace-ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7 X-SNX-Model: deepseek/deepseek-chat X-SNX-Provider: deepseek ``` ## 配额响应 触发用量配额限制(429)时可能包含: ```http Retry-After: 3600 ``` 值为建议等待秒数。 ## CORS 浏览器允许的请求头: - `Authorization` - `Content-Type` - `Accept-Language` - `X-Locale` ## 幂等 `Idempotency-Key` 是**请求**头(非响应头)。见 [Chat Completions](./chat-completions.md)。 ## 相关 - [Chat Completions](./chat-completions.md) - [错误处理](./errors.md) --- # Source: https://supanexus.ai/zh/docs/api/openai-sdk-integration.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # OpenAI SDK 集成 SupaNexus 可作为 OpenAI API 的 **即插即用替代**。只需修改 `base_url`(或 `baseURL`)和 `api_key`。 ## 配置对照 | OpenAI 默认 | SupaNexus 值 | |-------------|----------| | `https://api.openai.com/v1` | `/v1` | | OpenAI API Key | SupaNexus 项目 API Key | > 表中 `` 取值见 [接入点](./endpoints.md)。 ## Python ```python from openai import OpenAI client = OpenAI( base_url="/v1", api_key="whale-project-api-key", ) # 非流式 response = client.chat.completions.create( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "你好!"}], ) print(response.choices[0].message.content) # 流式 with client.chat.completions.stream( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "你好!"}], ) as stream: for event in stream: if event.type == "content.delta": print(event.delta, end="", flush=True) ``` ### 环境变量 ```bash export OPENAI_API_KEY="whale-project-api-key" export OPENAI_BASE_URL="/v1" ``` 许多读取 `OPENAI_*` 的工具可零代码切换。 ## Node.js / TypeScript ```typescript import OpenAI from "openai"; const client = new OpenAI({ baseURL: "/v1", apiKey: process.env.SNX_API_KEY, }); const response = await client.chat.completions.create({ model: "deepseek/deepseek-chat", messages: [{ role: "user", content: "你好!" }], }); console.log(response.choices[0]?.message?.content); ``` ## LangChain ```python from langchain_openai import ChatOpenAI llm = ChatOpenAI( base_url="/v1", api_key="whale-project-api-key", model="deepseek/deepseek-chat", ) ``` ## 与 OpenAI 的差异 | 主题 | SupaNexus 行为 | |------|------------| | 模型 id | 使用 `GET /v1/models` 返回的 `id`(如 `vendor/model`),非 OpenAI 模型名 | | Embeddings / Images | 路由已注册但返回 **501** — 尚未可用 | | 额外响应头 | Chat 上有 `X-SNX-Trace-ID`、`X-SNX-Model`、`X-SNX-Provider` | | 计费 | 按组织/项目计量;用量见控制台 | ## 路线图(尚未可用) 以下端点已注册但返回 HTTP **501**: - `POST /v1/embeddings` - `POST /v1/images/generations` 正式发布前请勿在生产集成中使用。 ## 相关 - [快速开始](./quickstart.md) - [模型](./models.md) - [流式响应](./streaming.md) --- # Source: https://supanexus.ai/zh/docs/api/anthropic-sdk-integration.md > **AI Agents**: 索引 `/api/llms.txt` | 英文全文 `/api/llms-full-en.txt` | 中文全文 `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Anthropic SDK 集成 将官方 Anthropic 客户端指向 SupaNexus 的 **`/v1/messages`** 端点。使用 SupaNexus API Key 进行 Bearer 认证。 > 示例中的 `` 取值见 [接入点](./endpoints.md)。 ## Python ```python import anthropic client = anthropic.Anthropic( api_key="sk-snx-...", # SupaNexus 项目 API Key base_url="", # 仅 host,不含 /v1;见接入点 ) message = client.messages.create( model="anthropic/claude-3-5-sonnet", max_tokens=1024, messages=[{"role": "user", "content": "你好!"}], ) print(message.content[0].text) ``` ## 环境变量 ```bash export ANTHROPIC_API_KEY="sk-snx-..." export ANTHROPIC_BASE_URL="" ``` ## Claude Code 将 base URL 设为 SupaNexus OpenAPI,SupaNexus API Key 作为 Anthropic API Key: ```bash export ANTHROPIC_BASE_URL="" export ANTHROPIC_API_KEY="sk-snx-..." ``` ## 说明 - 模型 id 须在 SupaNexus 目录中存在(`GET /v1/models`)。 - 此路径错误体为 Anthropic JSON 形态 — 见 [Messages](./messages.md)。 ## 相关 - [Messages](./messages.md) - [OpenAI SDK 集成](./openai-sdk-integration.md)