# Source: https://supanexus.ai/en/docs/api/endpoints.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL (Global): `https://api.supanexus.ai/v1` | CN: `https://api.supanexus.io/v1` # Endpoints SupaNexus provides two endpoints that share the **same account and API key**. Request paths, authentication, model list, and billing are identical — use either. Replace `` in other docs with a base URL from the table below. ## Base URLs | Site | Base URL | When to use | |------|----------|-------------| | Global | `https://api.supanexus.ai/v1` | Default endpoint | | CN | `https://api.supanexus.io/v1` | Backup endpoint | ## How to choose - Use Global by default. - If Global is unreachable or unstable, switch to the CN backup endpoint. - When switching, change only `base_url` / `SNX_BASE_URL` / `OPENAI_BASE_URL` (or equivalent). API key and other code stay the same. ## OpenAI SDK OpenAI-compatible paths include `/v1`: ```python from openai import OpenAI client = OpenAI( base_url="https://api.supanexus.ai/v1", # or "https://api.supanexus.io/v1" api_key="your-api-key", ) ``` ## Anthropic SDK Anthropic SDK `base_url` does **not** include `/v1`: ```python import anthropic client = anthropic.Anthropic( api_key="sk-snx-...", base_url="https://api.supanexus.ai", # or "https://api.supanexus.io" ) ``` ## Related - [Quickstart](./quickstart.md) - [OpenAI SDK Integration](./openai-sdk-integration.md) - [Anthropic SDK Integration](./anthropic-sdk-integration.md) --- # Source: https://supanexus.ai/en/docs/api/quickstart.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Quickstart Get your first chat completion from SupaNexus in under two minutes. ## Prerequisites 1. Access to the SupaNexus API (see [Endpoints](./endpoints.md)). 2. A **project API key** created in the [Developer Console](https://console.supanexus.ai). ## Base URL Examples below use the `` placeholder (usually with `/v1`): ``` /v1 ``` > Fill `` from [Endpoints](./endpoints.md). Replace `deepseek/deepseek-chat` with a model `id` from `GET /v1/models`. ## Send a chat completion ```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": "Say hello in one sentence."}] }' ``` ```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": "Say hello in one sentence."}], ) 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: "Say hello in one sentence." }], }); 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":"Say hello in one sentence."}]}`) 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":"Say hello in one sentence."}]} """; 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\":\"Say hello in one sentence.\"}]}"; 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: "Say hello in one sentence." }], }); 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: "Say hello in one sentence." }], }, ) 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" => "Say hello in one sentence."], ], ]), ]); $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": "Say hello in one sentence."}] })) .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 = "Say hello in one sentence." } }, }); 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":"Say hello in one sentence."}]} """.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":"Say hello in one sentence."}]} """.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":"Say hello in one sentence."}]}""" 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': 'Say hello in one sentence.'}, ], })); final response = await request.close(); final body = await response.transform(utf8.decoder).join(); print(body); client.close(); } ``` ## List available models ```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(); } ``` ## Next steps - [Authentication](./authentication.md) — API key format and errors - [Chat Completions](./chat-completions.md) — full request/response reference - [OpenAI SDK Integration](./openai-sdk-integration.md) — drop-in migration guide --- # Source: https://supanexus.ai/en/docs/api/authentication.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Authentication SupaNexus uses **Bearer API key** authentication, compatible with OpenAI client libraries. ## Header format ```http Authorization: Bearer ``` Include your API key secret in the `Authorization` header. SupaNexus validates the key on every request. ## Creating an API key 1. Sign in to the [Developer Console](https://console.supanexus.ai). 2. Open your organization → project → **API Keys**. 3. Create a key and copy the secret immediately (shown once). Each key is scoped to a **project** and **organization**. Usage is metered against that project. ## Expiration If the key has an expiration timestamp and is past due, requests return **401**: ```json { "error": { "code": 401, "message": "Invalid credentials. Provide a valid API key in the Authorization header." } } ``` ## Missing or invalid key | Condition | HTTP | Body | |-----------|------|------| | No `Authorization` header | 401 | `{"error":{"code":401,"message":"..."}}` | | Wrong or revoked key | 401 | Same | | Service temporarily unavailable | 503 | `{"error":{"code":503,"message":"..."}}` | ## Suspended account check After the API key is validated, SupaNexus also checks the **organization owner’s** platform account status: | Status | Console sign-in | API `/v1/*` | |--------|-----------------|-------------| | Active | Allowed | Allowed | | Suspended | Denied | **403** (see below) | Suspension is applied by a platform administrator. After unsuspension, console and API access resume. **API keys are not auto-revoked**, but the API rejects every request while the account is suspended. ```json { "error": { "code": 403, "message": "Your account has been suspended. Contact support for assistance." } } ``` Do not retry this error; contact SupaNexus support or your administrator. ## What authentication does not cover - **IP rate limiting** on `/v1/*` also returns OpenRouter-style 429 — see [Rate Limits & Quotas](./rate-limits-and-quotas.md). - **Usage quota and account balance checks** may run after authentication on `POST /v1/chat/completions` and `POST /v1/messages`, depending on your deployment. ## Security recommendations - Store keys in environment variables or a secrets manager, never in source control. - Rotate keys periodically and revoke unused keys in the console. - Use separate keys per environment (dev/staging/production). --- # Source: https://supanexus.ai/en/docs/api/chat-completions.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Chat Completions Create a model response for a multi-turn conversation. ``` POST /v1/chat/completions ``` > **Protocol note**: OpenAI-**shaped** entry for any sellable catalog model. Client shape and upstream protocol may differ; the gateway translates (e.g. `anthropic/*` → Anthropic Messages). For Claude images use [`/v1/messages`](./messages.md). ## Authentication Required: `Authorization: Bearer ` ## Request headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | Bearer API key | | `Content-Type` | Yes | `application/json` | | `Idempotency-Key` | No | Prevents duplicate calls within 24h | | `Accept-Language` / `X-Locale` | No | Affects localized error messages where applicable | ## Request body SupaNexus accepts the **OpenAI Chat Completions** JSON shape and reads `model` and `stream`; other fields follow OpenAI-compatible behavior. For multimodal input (`image_url`, and `video_url` as public URLs only), see [Parameters → Multimodal input](./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 } ``` | Field | Required | Description | |-------|----------|-------------| | `model` | Yes | Model id from `GET /v1/models` (e.g. `deepseek/deepseek-chat`) | | `messages` | Yes | Chat message array (OpenAI format) | | `stream` | No | `true` for SSE streaming — see [Streaming](./streaming.md) | ## Non-streaming response Returns OpenAI-compatible JSON. Example shape: ```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) counts input tokens served from **Prompt Cache**. SupaNexus uses this with [cached input pricing](/help/prompt-cache-pricing) when configured; otherwise all input tokens bill at the **input** rate. ## Usage and Prompt Cache billing SupaNexus does **not** run Prompt Cache but **reads** cache fields from the response `usage` for billing: | Provider | Typical field | |----------|----------------| | OpenAI | `usage.prompt_tokens_details.cached_tokens` | | Anthropic | `usage.cache_read_input_tokens` | Billing (simplified): ``` charge ≈ (prompt_tokens − cached_hit) × input_rate + cached_hit × cached_input_rate + completion_tokens × output_rate ``` See the [Models marketplace](https://console.supanexus.ai/models) for rates — [Model pricing](./model-pricing.md). Server-side usage records may include `cached_input_tokens`. ## Response headers (SupaNexus) | Header | Description | |--------|-------------| | `X-SNX-Trace-ID` | Unique request id for support | | `X-SNX-Model` | Model id used for this request | | `X-SNX-Provider` | Vendor identifier for the inference provider | ## Idempotency Send `Idempotency-Key: ` to deduplicate chat requests within **24 hours** per API key. If the same key was already processed: - **HTTP 409** - `error.code`: `duplicate_request` If `Idempotency-Key` is omitted, SupaNexus may fall back to `X-SNX-Trace-ID`. ## Routing SupaNexus selects an available service for your model id. If the request cannot be completed, you may receive **502** or **503**. ## Data and privacy SupaNexus **does not store conversation history across requests** — callers assemble `messages[]` on every call. | Handling | Description | |----------|-------------| | Request body | SupaNexus does **not** persist prompt/completion text by default | | Usage records | Call time, model, token counts, and billing-related metadata | | Support | Provide `X-SNX-Trace-ID` when contacting support | Chat history in the developer console **Text chat** playground lives only in the **current browser session**; SupaNexus does not restore it from the server after refresh or close. See [Privacy Policy](/privacy) and [Terms of Service](/terms). ## Common errors | HTTP | Meaning | |------|---------| | 400 | Missing `model`, invalid JSON, or illegal `video_url` (not public http(s)) | | 401 | Authentication failed | | 413 | Request body exceeds the default **64 MB** | | 402 | Insufficient account balance (`error.code=402`) | | 404 | Unknown or unavailable model | | 408 | Request timeout (default 120s) | | 409 | Idempotency conflict | | 429 | Usage quota exceeded | | 502 | Service temporarily unavailable | | 503 | Service temporarily unavailable | See [Errors](./errors.md) for full reference. ## Related - [Parameters](./parameters.md) - [Streaming](./streaming.md) - [Messages (Anthropic)](./messages.md) - [Model pricing](./model-pricing.md) - [Response Headers](./response-headers.md) --- # Source: https://supanexus.ai/en/docs/api/messages.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Messages (Anthropic-compatible) Create a model response using the **Anthropic Messages API** format — similar to [OpenRouter `/v1/messages`](https://openrouter.ai/docs/api/api-reference/anthropic-messages/create-messages). ``` POST /v1/messages ``` Use this endpoint when integrating **Anthropic SDK**, **Claude Code**, or other clients that expect native Anthropic shapes. Non-Anthropic upstreams are translated to OpenAI Chat Completions. Prefer this endpoint for Claude images. ## Authentication Required: `Authorization: Bearer ` (same SupaNexus API key as `/v1/chat/completions`). ## Request headers | Header | Required | Description | |--------|----------|-------------| | `Authorization` | Yes | Bearer API Key | | `Content-Type` | Yes | `application/json` | | `Idempotency-Key` | No | Deduplicate within 24h per API key | | `Accept-Language` / `X-Locale` | No | Localized error text where applicable | ## Request body SupaNexus accepts standard Anthropic Messages JSON and reads `model` and `stream`. ```json { "model": "anthropic/claude-3-5-sonnet", "max_tokens": 1024, "messages": [ {"role": "user", "content": "Hello!"} ], "stream": false } ``` | Field | Required | Description | |-------|----------|-------------| | `model` | Yes | Model id from `GET /v1/models` | | `messages` | Yes | Anthropic message array | | `max_tokens` | Yes | Maximum output tokens (Anthropic requirement) | | `system` | No | System prompt (string or content blocks) | | `stream` | No | `true` for Anthropic SSE events | | `temperature`, `top_p`, `stop_sequences` | No | Passed through when supported | | `tools`, `tool_choice`, `thinking`, `metadata` | No | Passed through in Anthropic-compatible form when supported | ## Multimodal input (images) When the model’s `architecture.input_modalities` includes `"image"`, `messages[].content` may be a **content-block array** carrying both text and images. ### Base64 image example ```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": "Describe this image"} ] } ] } ``` ### URL image example ```json { "type": "image", "source": { "type": "url", "url": "https://example.com/photo.jpg" } } ``` ### Limitation: OpenAI-protocol upstream models If the target model’s upstream uses the **OpenAI Chat Completions** protocol (not `anthropic/*`), Anthropic image blocks are **not** converted to `image_url`, and the upstream typically rejects the request. Use [`POST /v1/chat/completions`](./chat-completions.md) with OpenAI `image_url` instead — see [Parameters → Multimodal input](./parameters.md). **Rule of thumb**: for images, keep the client protocol aligned with the model’s upstream — use this endpoint for `anthropic/*`, and `/v1/chat/completions` for other models. ## Non-streaming response Anthropic-shaped JSON: ```json { "id": "msg_...", "type": "message", "role": "assistant", "model": "claude-3-5-sonnet-20241022", "content": [{"type": "text", "text": "Hello! How can I help?"}], "stop_reason": "end_turn", "usage": {"input_tokens": 12, "output_tokens": 8} } ``` ## Streaming When `stream: true`, SupaNexus returns Anthropic event-stream (`message_start`, `content_block_delta`, `message_delta`, `message_stop`). See [Streaming](./streaming.md) for general SSE notes. ## Response headers (SupaNexus) Same as Chat Completions: `X-SNX-Trace-ID`, `X-SNX-Model`, `X-SNX-Provider`. ## Error format On `/v1/messages`, SupaNexus returns **Anthropic-style** errors (not OpenRouter numeric `error.code`): ```json { "type": "error", "error": { "type": "invalid_request_error", "message": "you must provide a model parameter" } } ``` | HTTP | Typical `error.type` | |------|----------------------| | 400 | `invalid_request_error` | | 401 | `authentication_error` | | 402 | `billing_error` | | 404 | `not_found_error` | | 429 | `rate_limit_error` | | 503 | `overloaded_error` | For OpenRouter-shaped errors, use [`POST /v1/chat/completions`](./chat-completions.md) instead. ## OpenAI vs Anthropic endpoints | Client | Endpoint | Error body | |--------|----------|------------| | OpenAI SDK | `POST /v1/chat/completions` | OpenRouter `{error:{code,message}}` | | Anthropic SDK / Claude Code | `POST /v1/messages` | Anthropic `{type,error:{type,message}}` | Both use the **same SupaNexus API key** and share routing, quota, and billing. ## Related - [Anthropic SDK Integration](./anthropic-sdk-integration.md) - [Chat Completions](./chat-completions.md) - [Authentication](./authentication.md) - [Errors](./errors.md) --- # Source: https://supanexus.ai/en/docs/api/models.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Models List and retrieve models available to your API key. ## List models ``` GET /v1/models ``` ### Query parameters | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | `limit` | integer | 500 | Max items (1–1000) | ### Response ```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} } ] } ``` Only models **available to your API key** are returned. Unavailable or deprecated models are excluded. ## Retrieve model ``` GET /v1/models/{id} ``` The `{id}` path segment supports slashes (e.g. `deepseek/deepseek-chat`). ### Response Same object shape as a single entry in the list `data` array. ### Errors | HTTP | `error.code` | Cause | |------|--------------|-------| | 400 | — | Missing model id | | 404 | `model_not_found` | Unknown or not available for your key | | 502 | — | Model list temporarily unavailable | ## Model id format Use the **`id`** from `GET /v1/models` as the `model` parameter in chat requests (typically `{vendor}/{model}` such as `deepseek/deepseek-chat`). **Sell prices** (input / cached input / output) are **not** returned by this endpoint. See the [console Models marketplace](https://console.supanexus.ai/models) — [Model pricing](./model-pricing.md). ## Response fields List and detail responses may include metadata beyond the minimal OpenAI model object: | Field | Description | |-------|-------------| | `name` | Display name | | `context_length` | Max context window | | `architecture` | Input/output modalities (`input_modalities` / `output_modalities`; common values: `text`, `image`, `video`) | | `supported_parameters` | Parameters supported by the model | | `default_parameters` | Suggested defaults | Before sending images or video, check that the model’s `architecture.input_modalities` includes `"image"` / `"video"`. | Upstream type | Recommended endpoint | Request format | |---------------|----------------------|----------------| | Non-Anthropic (OpenAI-compatible upstream) | [`POST /v1/chat/completions`](./chat-completions.md) | `image_url` (URL or data URI); `video_url` (**public http(s) only**) — see [Parameters → Multimodal input](./parameters.md) | | `anthropic/*` (Anthropic Messages upstream) | [`POST /v1/messages`](./messages.md) | Anthropic image content blocks — see [Messages → Multimodal input](./messages.md) (video is not on this path) | Cross-protocol image requests (e.g. Chat Completions against Anthropic models, or Messages against OpenAI-protocol upstreams) are **unreliable** today: images may be dropped silently or rejected by the upstream. Pick the endpoint from the table above. Whale does **not** allow video as a data URI through the gateway. ## Related - [Chat Completions](./chat-completions.md) - [Model pricing](./model-pricing.md) - [Parameters](./parameters.md) --- # Source: https://supanexus.ai/en/docs/api/model-pricing.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Model pricing SupaNexus bills by **token usage**. OpenAPI `GET /v1/models` returns model metadata only — **not** sell prices. Use the **developer console → Models** marketplace as the source of truth. ## Where to see prices 1. Sign in to the [Developer Console](https://console.supanexus.ai). 2. Open **[Models](https://console.supanexus.ai/models)**. 3. Open a model’s detail page and check **Pricing**. When tiered pricing is configured, the detail page typically shows: | Tier | Meaning | |------|---------| | **Input** | New input tokens (not from cache) | | **Cached input** | Input tokens that hit Prompt Cache (usually cheaper) | | **Output** | Completion tokens | Some models may not have a public price yet — follow what the marketplace displays. ## OpenAPI vs billing | Scenario | Description | |----------|-------------| | List models | `GET /v1/models` — no prices | | Actual charges | After a successful `POST /v1/chat/completions` or `POST /v1/messages`, SupaNexus bills from token usage in the response (including cache hits) at the rates shown in the marketplace | See [Chat Completions — usage & Prompt Cache billing](./chat-completions.md#usage-prompt-cache-and-billing) for the simplified formula. ## Related - [Models](./models.md) — OpenAPI `GET /v1/models` - [Help: Billing & balance](/help/billing) - [Help: Cached input & Prompt Cache pricing](/help/prompt-cache-pricing) --- # Source: https://supanexus.ai/en/docs/api/streaming.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Streaming Stream chat completion tokens using **Server-Sent Events (SSE)**. ## Enable streaming Set `"stream": true` in the chat completions request body: ```json { "model": "deepseek/deepseek-chat", "messages": [{"role": "user", "content": "Count to five."}], "stream": true } ``` **Use `stream: true` for reasoning / long-thinking models.** Non-streaming requests may be cut off by CDN (e.g. Cloudflare) ~100s first-byte limits. On the streaming path the gateway periodically sends SSE comment lines (`: keepalive`), which SDKs ignore. ## Response format - **Content-Type**: `text/event-stream` - Each line: `data: ` - Terminator: `data: [DONE]` Example (`data:` JSON is usually one line on the wire; line breaks here are for readability): ```http data: { "id": "chatcmpl-...", "object": "chat.completion.chunk", "choices": [ { "index": 0, "delta": { "content": "One" }, "finish_reason": null } ] } data: { "id": "chatcmpl-...", "object": "chat.completion.chunk", "choices": [ { "index": 0, "delta": { "content": ", two" }, "finish_reason": null } ] } data: [DONE] ``` ## Usage in stream The final stream chunks may include a `usage` object with token counts (model-dependent). ## curl example ```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": "Say hi"}] }' ``` Use `-N` to disable curl buffering. ## OpenAI SDK (Python) ```python stream = client.chat.completions.create( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "Say hi"}], stream=True, ) for chunk in stream: delta = chunk.choices[0].delta.content or "" print(delta, end="", flush=True) ``` ## Error handling | Phase | Behavior | |-------|----------| | **Pre-stream** | HTTP 4xx/5xx with JSON `error` object (same as non-streaming) | | **Mid-stream** | Client should handle truncated SSE | Quota, balance, and auth errors typically occur **before** the first byte of the stream. ## Related - [Chat Completions](./chat-completions.md) - [Errors](./errors.md) --- # Source: https://supanexus.ai/en/docs/api/parameters.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Parameters Request parameters for `POST /v1/chat/completions`. ## Required | Parameter | Type | Description | |-----------|------|-------------| | `model` | string | Model id from `GET /v1/models` | | `messages` | array | OpenAI chat messages; `content` may be a string or a content-part array (text + images / video, etc.) | ## Common optional parameters SupaNexus **passes through** standard OpenAI parameters when the model supports them. Check `supported_parameters` on the model object. | Parameter | Type | Description | Example | |-----------|------|-------------|---------| | `stream` | boolean | **Stream tokens** as they are generated; use `true` for chat UIs, `false` for batch jobs | `"stream": true` | | `temperature` | number | **Randomness**: higher = more creative; lower = more stable and repeatable. Try `0.7` for chat, `0`–`0.3` for factual Q&A | `"temperature": 0.7` | | `top_p` | number | Another randomness control (nucleus sampling); usually tune **either** this **or** `temperature`, not both aggressively | `"top_p": 0.9` | | `max_tokens` | integer | **Cap reply length** in tokens — avoids overly long answers or runaway cost | `"max_tokens": 1024` | | `frequency_penalty` | number | **Discourage repeating the same words** — higher values reduce “looping” phrasing | `"frequency_penalty": 0.5` | | `presence_penalty` | number | **Encourage new topics** — higher values reduce staying stuck on one point | `"presence_penalty": 0.3` | | `stop` | string or array | Generation **stops** when the model outputs these strings — useful for sections or lists | `"stop": ["\n\n", "END"]` | | `tools` | array | Declare **functions the model may call** (weather, orders, etc.); requires Function Calling support | See example below | | `tool_choice` | string or object | Tool policy: `"auto"` (model decides), `"none"` (disable), `"required"` (must call a tool) | `"tool_choice": "auto"` | | `response_format` | object | Force a **structured output** shape, e.g. valid JSON only | `"response_format": {"type": "json_object"}` | | `user` | string | **End-user id** in your app — helps abuse tracking; on OpenAI models can also improve Prompt Cache hit rate | `"user": "user-42"` | `tools` example (simplified): ```json "tools": [ { "type": "function", "function": { "name": "get_weather", "description": "Get current weather for a city", "parameters": { "type": "object", "properties": { "city": { "type": "string", "description": "City name, e.g. Shanghai" } }, "required": ["city"] } } } ] ``` ## Multimodal input When the model supports vision or video, `messages[].content` may be a **content-part array** (OpenAI-compatible format). Confirm via `GET /v1/models` that `architecture.input_modalities` includes `"image"` for images and/or `"video"` for video. Text-only models (`["text"]` only) reject media. ### Images (`image_url`) #### Image URL example ```json { "model": "google/gemini-2.5-flash", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Describe this image"}, { "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } } ] } ] } ``` #### Base64 image example Set `image_url.url` to a data URI: ```json { "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,/9j/4AAQSkZJRg..." } } ``` Base64 inflates the body by about **33%**. The default body limit is **64 MB**; exceeding it returns **413** with `error.code` `request_too_large`. Prefer a publicly reachable URL for large images. ### Video (`video_url`) When `input_modalities` includes `"video"` (e.g. `minimax/minimax-m3`, `moonshot/kimi-k2.6`), use a `video_url` content part. **Whale v1 policy**: | Allowed | Not allowed | |---------|-------------| | Public `http://` / `https://` video URLs (upstream fetches the media) | `data:` (base64), `file://`, `blob:`, vendor file refs (e.g. `mm_file://`, `ms://`) | Invalid `video_url` values are rejected with **400** and are not forwarded. Do not send video as a data URI through the gateway — that would consume platform bandwidth. #### Public video URL example ```json { "model": "minimax/minimax-m3", "messages": [ { "role": "user", "content": [ {"type": "text", "text": "Summarize this video"}, { "type": "video_url", "video_url": { "url": "https://example.com/demo.mp4", "detail": "default" } } ] } ] } ``` Some upstreams also accept fields such as `fps` for frame sampling; they are passed through when supported. ### Limitation: Anthropic upstream models When an OpenAI client (`POST /v1/chat/completions`) calls **`anthropic/*`**, the gateway translates the request and flattens messages to plain text — **images are dropped silently**. For images use [`POST /v1/messages`](./messages.md). **Rule of thumb**: for images, align client protocol with upstream — `/v1/messages` for `anthropic/*`, `/v1/chat/completions` otherwise. ## Request handling ### Recognized fields - `model` — model id for this call - `stream` — SSE streaming vs JSON response ### Streaming usage When `stream: true`, the response may include a `usage` object at the end (model-dependent). ### Other parameters Remaining JSON fields are handled in an OpenAI-compatible way within body size limits. ## Body size limit Default maximum request body: **64 MB** (`GATEWAY_OPENAPI_MAX_REQUEST_BODY_BYTES`). Exceeding the limit returns **413** with `error.code` `request_too_large`. Large images may use data URIs; **large videos must use a public URL** — do not base64-encode video into the request body. ## Model-specific defaults Each model may expose `default_parameters` in `GET /v1/models`. These are suggested defaults; the client may override them in the request. ## Related - [Models](./models.md) - [Chat Completions](./chat-completions.md) - [Messages (Anthropic)](./messages.md) - [Errors](./errors.md) --- # Source: https://supanexus.ai/en/docs/api/errors.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Errors SupaNexus API (`/v1/*`) uses **[OpenRouter-compatible errors](https://openrouter.ai/docs/api/reference/errors-and-debugging)**: `error.code` is a **number** equal to the HTTP status. ## Error JSON format ```json { "error": { "code": 402, "message": "Your account or API key has insufficient credits. Add more credits and retry the request.", "metadata": {} } } ``` | Field | Description | |-------|-------------| | `error.code` | **Integer** matching the HTTP response status | | `error.message` | Human-readable description | | `error.metadata` | Optional extension (e.g. provider error details) | ## HTTP status reference | HTTP | When | |------|------| | 400 | Invalid parameters, JSON parse failure; `video_url` that is not a public http(s) URL (including data URIs, file, or vendor private schemes) | | 401 | Missing, wrong, or expired API key | | 413 | Request body exceeds the limit (default **64 MB**, `error.code` = `request_too_large`) | | 402 | Insufficient account or API key credits | | 403 | Account suspended, permission denied, or missing org/project context | | 404 | Model not found or not sellable | | 408 | Request timeout | | 409 | Idempotency key reused | | 429 | Rate or usage quota exceeded (`Retry-After` may be set) | | 501 | Embeddings / images not implemented yet | | 502 | Service temporarily unavailable | | 503 | Service temporarily unavailable | | 500 | Internal service error | ## Account suspended (403) When a platform user is suspended by an administrator, every `/v1/*` request fails after API key validation with: ```json { "error": { "code": 403, "message": "Your account has been suspended. Contact support for assistance." } } ``` - Independent of whether the key itself is still valid (non-revoked keys can still receive this error) - Access resumes immediately after unsuspension; no need to recreate keys - See [Authentication — Suspended account check](./authentication.md#suspended-account-check) ## Retry guidance | HTTP | Retry? | Notes | |------|--------|-------| | 401 | No | Fix API key | | 403 | No | Contact admin if suspended; otherwise check permissions and context | | 402 | No | Add credits or contact your administrator | | 404 | No | Use a valid model id | | 408 | Maybe | Reduce payload or increase client timeout | | 409 | No | Use a new idempotency key | | 429 | Yes | Respect `Retry-After` when present | | 502 | Maybe | Exponential backoff, then retry | | 503 | Maybe | Short backoff | ## Service auth failures If the inference provider rejects credentials, SupaNexus typically returns **502** with message `"Upstream authentication failed."` rather than exposing provider details. ## Anthropic `/v1/messages` errors On `POST /v1/messages`, SupaNexus returns **Anthropic-shaped** JSON instead of OpenRouter numeric codes: ```json { "type": "error", "error": {"type": "authentication_error", "message": "Invalid API key"} } ``` See [Messages](./messages.md) for field reference. Chat Completions continues to use the OpenRouter format above. ## Streaming errors Errors that occur **before** streaming starts use the JSON format above with the appropriate HTTP status. See [Streaming](./streaming.md). ## Related - [Rate Limits & Quotas](./rate-limits-and-quotas.md) - [Authentication](./authentication.md) --- # Source: https://supanexus.ai/en/docs/api/rate-limits-and-quotas.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Rate Limits & Quotas SupaNexus may apply multiple independent limit layers. Exact thresholds depend on your deployment — check with your platform administrator or the Developer Console. ## 1. IP rate limit Applies to **all routes** (including requests without a valid API key), scoped by client IP. Typical default: about **120 requests per minute** per IP (when enabled). When exceeded: - **HTTP 429** - OpenRouter format (same on `/v1/*` and other routes): ```json { "error": { "code": 429, "message": "You are being rate limited." } } ``` The response may include a **`Retry-After`** header (seconds). > **Note:** This limit is per **IP address**, not per API key. ## 2. Usage quota (optional) May apply to `POST /v1/chat/completions` only when configured for your organization or project. When exceeded: - **HTTP 429** - `error.code`: **429** (numeric) - **`Retry-After`** header may be set (seconds) ## 3. Account balance (optional) May apply to `POST /v1/chat/completions` only when prepaid credits or balance checks are enabled. | HTTP | Meaning | |------|---------| | 402 | Not enough credits for this period (`error.code=402`) | | 403 | Organization context missing | **402 vs 429:** Insufficient balance uses **402 Payment Required**. Quota or spend-cap limits use **429 Too Many Requests**. ## Comparison table | Layer | Typical scope | Error format | HTTP | |-------|---------------|--------------|------| | IP rate limit | All routes | OpenRouter `{error:{code,message}}` | 429 | | Usage quota | Chat only | OpenRouter | 429 | | Account balance | Chat only | OpenRouter | 402 | ## Best practices - Implement exponential backoff on 429 and respect `Retry-After`. - Use separate API keys per application to simplify usage tracking in the console. - Monitor usage in the Developer Console before hitting limits. ## Related - [Errors](./errors.md) - [Chat Completions](./chat-completions.md) --- # Source: https://supanexus.ai/en/docs/api/response-headers.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Response Headers SupaNexus adds diagnostic headers on API responses. ## Global headers | Header | Present on | Description | |--------|------------|-------------| | `X-SNX-Trace-ID` | All responses | Unique request id; include in support tickets | ## Chat completions headers | Header | Present on | Description | |--------|------------|-------------| | `X-SNX-Model` | `POST /v1/chat/completions` | Logical model id requested | | `X-SNX-Provider` | `POST /v1/chat/completions` | Vendor identifier for the inference provider | Example: ```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 ``` ## Quota responses When a usage quota limit applies, SupaNexus may include: ```http Retry-After: 3600 ``` Value is seconds until retry is suggested. ## CORS SupaNexus allows these request headers from browsers: - `Authorization` - `Content-Type` - `Accept-Language` - `X-Locale` ## Idempotency `Idempotency-Key` is a **request** header (not a response header). See [Chat Completions](./chat-completions.md). ## Related - [Chat Completions](./chat-completions.md) - [Errors](./errors.md) --- # Source: https://supanexus.ai/en/docs/api/openai-sdk-integration.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # OpenAI SDK Integration SupaNexus is a **drop-in replacement** for OpenAI's API when using official OpenAI SDKs. Change only `base_url` (or `baseURL`) and `api_key`. ## Configuration | OpenAI default | SupaNexus value | |----------------|-------------| | `https://api.openai.com/v1` | `/v1` | | OpenAI API key | SupaNexus project API key | > Fill `` from [Endpoints](./endpoints.md). ## Python ```python from openai import OpenAI client = OpenAI( base_url="/v1", api_key="whale-project-api-key", ) # Non-streaming response = client.chat.completions.create( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "Hello!"}], ) print(response.choices[0].message.content) # Streaming with client.chat.completions.stream( model="deepseek/deepseek-chat", messages=[{"role": "user", "content": "Hello!"}], ) as stream: for event in stream: if event.type == "content.delta": print(event.delta, end="", flush=True) ``` ### Environment variables ```bash export OPENAI_API_KEY="whale-project-api-key" export OPENAI_BASE_URL="/v1" ``` Many tools that read `OPENAI_*` env vars work without code changes. ## 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: "Hello!" }], }); 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", ) ``` ## Differences from OpenAI | Topic | SupaNexus behavior | |-------|----------------| | Model ids | Use the `id` from `GET /v1/models` (e.g. `vendor/model`), not OpenAI model names | | Embeddings / Images | Routes exist but return **501** — not yet available | | Extra headers | `X-SNX-Trace-ID`, `X-SNX-Model`, `X-SNX-Provider` on chat | | Billing | Metered per organization/project; see console for usage | ## Roadmap (not available yet) These endpoints are registered but return HTTP **501**: - `POST /v1/embeddings` - `POST /v1/images/generations` Do not use them in production integrations until announced. ## Related - [Quickstart](./quickstart.md) - [Models](./models.md) - [Streaming](./streaming.md) --- # Source: https://supanexus.ai/en/docs/api/anthropic-sdk-integration.md > **AI Agents**: Index `/api/llms.txt` | Full EN `/api/llms-full-en.txt` | Full ZH `/api/llms-full-zh.txt` | OpenAPI `/api/openapi.yaml` > Base URL: `/v1` # Anthropic SDK Integration Point the official Anthropic client at SupaNexus's **`/v1/messages`** endpoint. Use your SupaNexus API key with Bearer authentication. > Fill `` from [Endpoints](./endpoints.md). ## Python ```python import anthropic client = anthropic.Anthropic( api_key="sk-snx-...", # SupaNexus project API key base_url="", # host only, no /v1; see Endpoints ) message = client.messages.create( model="anthropic/claude-3-5-sonnet", max_tokens=1024, messages=[{"role": "user", "content": "Hello!"}], ) print(message.content[0].text) ``` ## Environment variables ```bash export ANTHROPIC_API_KEY="sk-snx-..." export ANTHROPIC_BASE_URL="" ``` ## Claude Code Set the base URL to SupaNexus OpenAPI and use your SupaNexus API key as the Anthropic API key: ```bash export ANTHROPIC_BASE_URL="" export ANTHROPIC_API_KEY="sk-snx-..." ``` ## Notes - Model ids must exist in SupaNexus catalog (`GET /v1/models`). - Errors on this path use Anthropic JSON shape — see [Messages](./messages.md). ## Related - [Messages](./messages.md) - [OpenAI SDK Integration](./openai-sdk-integration.md)