NezhaGateNezhaGate
POST https://nezhagate.com/v1/chat/completions

Claude Sonnet 4.6 chat API (Anthropic), balancing capability and speed for everyday chat, coding and agents, with a context window of about 200K tokens, image input and tool calls. Served on the OpenAI-compatible API and the native Anthropic API.

📥 Context window (max input):~200K tokens.

Try in Playground →

Quick start

Two steps: send a request, then stream the answer. Replace YOUR_API_KEY with your key and the commands below run as they are. The endpoint matches OpenAI Chat Completions, so existing OpenAI code only needs a new base_url and model.

Step 1 · Send a request

curl
curl https://nezhagate.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "Explain photosynthesis in one sentence"}]}'

Response (HTTP 200)

JSON
{
  "id": "chatcmpl-7f3c9a1e2b4d6f8a",
  "object": "chat.completion",
  "created": 1791281400,
  "model": "claude-sonnet-4-6",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Photosynthesis is how plants use sunlight to turn carbon dioxide and water into sugar, releasing oxygen."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 18,
    "completion_tokens": 42,
    "total_tokens": 60
  }
}

message.content is the answer and usage holds the tokens this request is billed for; for how prompt caching bills, see Prompt caching below.

Step 2 · Stream the answer (recommended)

curl
curl -N https://nezhagate.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "stream": true, "messages": [{"role": "user", "content": "Explain photosynthesis in one sentence"}]}'

The stream is standard SSE: each chunk carries text in choices[0].delta.content, the last chunk carries usage, and it ends with data: [DONE]. Stream long answers and thinking models: a non-streaming request is cut off after about 10 minutes.

Python (OpenAI SDK)

Python
from openai import OpenAI

client = OpenAI(base_url="https://nezhagate.com/v1", api_key="YOUR_API_KEY")

# 1. One request, one answer
resp = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "Explain photosynthesis in one sentence"}],
)
print(resp.choices[0].message.content)

# 2. Streaming
stream = client.chat.completions.create(
    model="claude-sonnet-4-6",
    messages=[{"role": "user", "content": "Explain photosynthesis in one sentence"}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

Or use the Anthropic SDK (native API)

Python · Anthropic SDK
import anthropic

client = anthropic.Anthropic(base_url="https://nezhagate.com/anthropic", api_key="YOUR_API_KEY")
msg = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain photosynthesis in one sentence"}],
)
print(next(b.text for b in msg.content if b.type == "text"))

Point the Anthropic SDK base_url at /anthropic and the SDK adds /v1/messages itself; the key is the same one.

Authentication

Header
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

Create an API Key in the console to start.

At a glance

Context window~200K tokens
InputText, images
ThinkingOff by default; can be turned on, with summaries, on the native API
Tool callingYes (OpenAI tools format)
Web searchYes (web_search: true; the search itself is free)
Endpoints/v1/chat/completions · /anthropic/v1/messages
StreamingYes (stream: true, SSE)
BillingPer token: input, output (thinking included) and cache hits each have a price; failures are free

Request parameters

The JSON body of POST /v1/chat/completions, the same as OpenAI Chat Completions. The common parameters, and what each one does on this model:

ParameterTypeRequiredDescription
modelstringYesThe model id: claude-sonnet-4-6.
messagesarrayYesThe conversation: each message has a role (system, user, assistant or tool) and content. content is a string, or an array of text and image_url parts (image input, see below). For multi-turn chat, send the whole history in order.
streambooleanNotrue streams the answer as SSE, with usage in the last chunk. Defaults to false.
max_tokensintegerNoThe output cap, thinking tokens included. Set too low, the model can spend it all before writing the answer: the gateway then returns 400 max_tokens_too_small and bills nothing (512 or more is recommended). On some models a value that is too small is raised to a floor that leaves room for a full answer, still billed on actual usage only.
temperature / top_pnumberNoSampling parameters, passed to the model as sent (temperature from 0 to 2). Thinking models may not follow them.
tools / tool_choicearray / stringNoFunction calling in the standard OpenAI format. When the model calls a function it returns finish_reason: "tool_calls" with tool_calls; see below.
web_searchbooleanNotrue runs a web search first and hands the results to the model as reference; see below.

Other OpenAI parameters (such as stop, seed, user) are passed to the model as sent; whether they take effect is up to the model.

Price

Billed per token at the live rates below (per million tokens). Tokens written to the prompt cache bill at the cache-write rate and cache hits at the cache-hit rate. Only successful requests are billed, on actual usage. 1 credit = $0.005.

TypeUSD / 1M tokensCredits / 1M tokens
Input$1.50300
Output (thinking included)$7.501500
Cache hit$0.1530
Cache write$1.875375

For example, a request with 2,000 input tokens and 1,000 output tokens (thinking included) costs about $0.0105.

Thinking

Answers directly by default, without thinking. To turn thinking on and get a summary, use the native /anthropic API with "thinking": {"type": "adaptive", "display": "summarized"} in the request.

Thinking tokens count as output tokens and bill at the output price.

Prompt caching

Long prompts may be written to the cache automatically even without a marker (billed at the cache-write rate), and a repeated prefix then bills at the cache-hit rate. On the native /anthropic API you can place the cache yourself with "cache_control": {"type": "ephemeral"} on the system prompt or a message block; Claude Code does this for you.

The native API reports cached tokens in usage.cache_creation_input_tokens (written) and usage.cache_read_input_tokens (hits), and the bill uses those numbers.

Image input

Put an image_url part in the content array. A base64 data URI (data:image/png;base64,...) is the recommended form and can always be read; a public image link has to be downloaded first, and occasionally it cannot be fetched or times out. Images count as input tokens by the model vendor rules.

curl
curl https://nezhagate.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": [{"type": "text", "text": "What is in this image"}, {"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo..."}}]}]}'

Tool calling (function calling)

Describe your functions in tools with JSON Schema. When the model decides to call one, it returns finish_reason: "tool_calls" with the function name and arguments (a JSON string) in message.tool_calls.

curl
curl https://nezhagate.com/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "messages": [{"role": "user", "content": "What is the weather in Shanghai right now"}], "tools": [{"type": "function", "function": {"name": "get_weather", "description": "Current weather of a city", "parameters": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]}}}]}'

Run the function, append the result as a role: "tool" message with the matching tool_call_id, and send the conversation again; the model then gives its final answer. tool_choice takes auto, none, required or a named function.

The native Anthropic API (/anthropic)

  • The endpoint is https://nezhagate.com/anthropic/v1/messages, and requests and responses use the Anthropic Messages format: streaming events, tool calls (tool_use / tool_result) and image blocks all match Anthropic, so the Anthropic SDK and Claude Code work as they are.
  • Authenticate with x-api-key: YOUR_API_KEY (Authorization: Bearer works too); the key is the same one as on /v1. The anthropic-version and anthropic-beta headers are passed on as sent, and max_tokens is required.
  • Only Claude models are served here; any other model returns 404 not_found_error. Also available: POST /anthropic/v1/messages/count_tokens (counts tokens, free) and GET /anthropic/v1/models.
  • Turn thinking on with "thinking": {"type": "adaptive", "display": "summarized"} (with thinking on, temperature must be 1).
  • Errors come back in the Anthropic format, {"type": "error", "error": {"type": ..., "message": ...}}; too little balance returns 402 billing_error.
  • Web search is off by default on this endpoint (so it never changes the prefix Claude Code repeats on every turn and breaks its cache); turn it on with the x-web-search: 1 header.
curl
curl https://nezhagate.com/anthropic/v1/messages \
  -H "x-api-key: YOUR_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-sonnet-4-6", "max_tokens": 1024, "messages": [{"role": "user", "content": "Explain photosynthesis in one sentence"}]}'

Use it in Claude Code →

Reliability and automatic retries

  • When a request errors, times out or hits a capacity limit, the gateway retries it automatically before anything is returned, so you need not retry and are never billed twice.
  • Once a stream starts sending, it is no longer retried automatically: if it breaks partway, you are billed for the usage produced up to that point (see Billing and refunds).
  • When the model is at capacity the gateway returns 429 with Retry-After; wait that many seconds and retry. Failed requests are not billed. Each model status is on the status page.

Errors and refunds

Errors come back as an error object (message, type, code, param); decide by the HTTP status and code, never by matching the text of message. Failed requests are not billed; the full list is in Error codes.

HTTPcodeCauseWhat to do
400invalid_messages / invalid_role / invalid_max_tokensA chat request's messages is missing, empty or malformed, a role is not one of the allowed values, or max_tokens is not a positive integer. param names the field.Fix the field named in param.
400model_not_foundThe model id is misspelled, model is missing, or the model cannot be used on this endpoint (a chat model on the image endpoint, for example).Use a model id from GET /v1/models or the API reference.
400max_tokens_too_smallA reasoning model spent all of max_tokens thinking and wrote no answer (non-streaming chat).Raise max_tokens and retry.
4xxinvalid_requestThe model provider rejected the request (an over-long context or an unsupported parameter, for example); the status and message are passed on as the provider sent them, and code is the provider's value.Change the request as message says.
401invalid_api_keyThe key does not exist, was deleted or is disabled, or the account is disabled.Check the key on the API Keys page of the console.
402insufficient_quotaNot enough balance to hold this request. The gateway holds the highest possible cost of the request first, so a burst of concurrent calls can trigger it too.After a burst, wait a few seconds and retry; otherwise top up.
403permission_deniedThe model is not on the key's model allowlist.Use a model on the allowlist, or edit the allowlist in the console.
429rate_limit_exceededOver the requests-per-minute limit set on this key (counted over the last 60 seconds). No Retry-After header.Wait a few seconds and retry, or raise the key's limit in the console.
429rate_limit_exceededThe model is at capacity and the request was not sent. Chat endpoints only: image and video jobs are never refused but queue instead. The OpenAI-compatible endpoints add Retry-After.Wait the seconds in Retry-After, then retry.
502upstream_timeoutThe upstream timed out, including taking too long to send the first token.Retry; use stream: true for long answers.
502upstream_unavailableThe upstream failed or is unavailable for the moment.Retry shortly.
502upstream_busyThe model provider is rate-limiting. A provider's 429 is never passed on as a 429; you get this 502 instead.Retry shortly.
502empty_completionThe model provider returned empty content. This is not a judgement of your content.Retry.
503model_maintenanceThe model is under maintenance and takes no requests; no other model answers in its place meanwhile.Retry when maintenance ends; see Status.

If a stream fails after it started sending, the status code stays as it was: the error arrives as a data line carrying error, or the stream just ends (without data: [DONE]). Treat it as interrupted.