Chat Completions

Generate a model response for a conversation. This is the core endpoint. It follows OpenAI's Chat Completions request and response format, so the OpenAI SDKs work once you set the SovereignEG base URL and API key. Differences to know:

  • Running out of credit returns HTTP 402 (insufficient_quota), not 429. One exception: a request naming its model whose credit is held by your organization's other requests still running gets 429 inflight_busy with Retry-After (a streaming request after waiting up to about 25 seconds for them, a non-streaming one at once or after up to about 10); retry it (see Rate Limits). A model: "auto" request can get either: the 402 when what the running requests leave is too little for its classification step or for every model in its auto pool, the 429 when the chosen model's gate refuses it.
  • Streamed responses include token usage even if you did not set stream_options (see Streaming).
  • The response model is the id reported by the model that served the request, and it can differ from the id you sent.
  • n is capped at 8.
  • Parameters the gateway does not recognise are ignored rather than rejected.
  • If your balance cannot pay for the full output, or the monthly spend cap on your API key or project has less left than it would cost, max_tokens is lowered and the response carries X-Output-Clamped, streaming requests included. On a model that can reason before it answers where you cannot see it (Claude, OpenAI GPT-5 and o-series, Gemini thinking models, Grok), a streaming request's max_tokens is never lowered below 1,024 output tokens: the reasoning is billed as output and could use up a smaller cap and leave an empty answer, so below that the request is refused instead (a cap of your own that already fits is served as is). A stream that runs out of credit part-way ends cleanly with finish_reason: "length" and stop_reason: "balance_exhausted" on its last chunk ("spend_cap_reached" when a spend cap is what ran out: you are never billed past a cap; see Streaming).
  • On a Student or Developer plan's free-allowance models, replies are capped at the plan's output limit; when that cap lowers your max_tokens, or sets one because you sent none, the response carries X-Plan-Output-Cap: <n> and the reply can stop early with finish_reason: "length". These models also run one completion per request (n must be 1).
  • Claude models served directly by Anthropic reject OpenAI-only parameters (seed, logprobs, logit_bias, non-zero penalties, n > 1) with a 400.

Endpoint

POST https://backend.sovereigneg.com/v1/chat/completions

Request body

ParameterTypeRequiredDescription
modelstringYesModel ID from GET /v1/models or the Model Library
messagesarrayYesConversation messages (see below)
temperaturefloatNoSampling temperature (0.0–2.0). Default: 1.0. Not sent to Claude Opus 4.7 and later models; see Sampling on Claude Opus 4.7 and later below
max_tokensintegerNoMax tokens to generate (max_completion_tokens is also accepted and takes precedence). Must not exceed the model's context window (400 max_tokens_exceeded). Default: model-dependent. If your remaining balance, or what is left of your API key's or project's monthly spend cap, cannot pay for the full output, the gateway lowers this cap (or sets one if you sent none) to what the balance can buy and returns X-Output-Clamped: <n>; the reply can then stop early with finish_reason: "length". A streaming request is lowered the same way, except on a model that reasons out of sight (Claude, OpenAI GPT-5 and o-series, Gemini thinking models, Grok), whose cap is never lowered below 1,024: below that the request is refused (402 insufficient_balance, or 429 inflight_busy after waiting up to about 25 seconds for them while your other requests still running hold the credit). With no max_tokens at all, such a streaming request may be lowered to half of what your balance buys, so a second request can run beside it
top_pfloatNoNucleus sampling (0.0–1.0). Default: 1.0. Not sent to Claude Opus 4.7 and later models; see Sampling on Claude Opus 4.7 and later below
streambooleanNoStream response via SSE. Default: false
stopstring/arrayNoStop sequences
frequency_penaltyfloatNoFrequency penalty (-2.0 to 2.0). Default: 0.0
presence_penaltyfloatNoPresence penalty (-2.0 to 2.0). Default: 0.0
reasoning_effortstringNoReasoning depth on models that reason: none, minimal, low, medium, high, xhigh. Dropped on models that do not reason and mapped to the nearest value the selected model accepts. On OpenAI's gpt-5.6, gpt-6 and later chat models (not gpt-6-astra or the -pro and chat-latest SKUs), a request with function tools and a reasoning_effort other than none is sent to OpenAI with none, because OpenAI does not accept function tools together with another value on chat completions, and X-Mapped-Params says so. Left unset, Claude 5.x models still think, at their own default effort, and that hidden thinking is billed as output; see Parameter adjustments below

Parameter adjustments

Agent frameworks send reasoning_effort on every request, including to models that do not reason. Instead of failing the request with the provider's 400, the gateway adjusts the parameter for the selected model and names the adjustment in a response header:

HeaderMeaning
X-Dropped-Params: reasoning_effortThe model does not reason (for example gpt-4o-mini), or the gateway does not pass the value on for that model (Claude Opus 4.8, 4.7 and 4.6, Sonnet 4.6, and Claude 4.5 and older models, which do not think unless asked; and Claude models newer than the gateway's table, which receive no thinking settings until they are added: they think by default with the thinking hidden, and that thinking is billed as output), so the field was removed before the request reached the provider.
X-Mapped-Params: reasoning_effort=<value>The model reasons but does not accept the value you sent; <value> is what it received (for example none becomes minimal on gpt-5-mini, and high becomes xhigh on SovereignEG/Qwen3.8-27B-FP8).

X-Dropped-Params is a comma-separated list of the parameters the gateway left out, reasoning_effort first. It also names the sampling parameters a Claude model served by Anthropic did not receive (see Sampling on Claude Opus 4.7 and later), for example X-Dropped-Params: reasoning_effort, temperature, so look for a name in the list instead of comparing the whole value. Neither header names reasoning_effort when the value went through unchanged. Claude models served directly by Anthropic:

  • none. The model does not think, so the whole max_tokens goes to the answer you see. This applies to Claude Haiku 5.5, Sonnet 5.5, Sonnet 5 and Opus 5. In a tool loop, Sonnet 5.5 can still write short progress notes between tool calls; they arrive as reasoning_content. Claude Opus 5.5 and the Fable models cannot stop thinking. They think at the lowest effort instead, and none is reported as X-Mapped-Params: reasoning_effort=low.
  • No reasoning_effort. No thinking setting is sent, so the model thinks at its own default effort, with or without tools: Claude Haiku 5.5, Sonnet 5.5, Sonnet 5, Opus 5, Opus 5.5 and the Fable models all think by default. That thinking is not shown, but it is billed as output and counts toward max_tokens, so a small max_tokens can run out before the answer starts. To keep the cost down, send none or low, or set max_tokens, which caps thinking and answer together.
  • minimal to xhigh. The model thinks at that effort (minimal is sent as low). Its reasoning streams as reasoning_content before the answer, unless you set include_reasoning: false.

Thinking counts toward max_tokens and is billed as output, including thinking you do not see: thinking at the model's own default (no reasoning_effort) and lowest-effort thinking (none on Opus 5.5 and Fable) are not shown, and neither is any thinking when you set include_reasoning: false. When Anthropic reports the thinking share, the response carries it in usage.completion_tokens_details.reasoning_tokens, which is part of completion_tokens, not added to it. A small max_tokens with reasoning on can run out before the answer starts and end with finish_reason: "length". A refused answer ends with finish_reason: "content_filter". If you close a stream before it ends, you are billed for the output generated until then. When the model was thinking, that output is estimated from the time it spent thinking. The estimate is deliberately on the high side, so it can be more than the exact count the finished stream would have reported, and it never exceeds max_tokens.

When Anthropic is overloaded or failing, a Claude request can fail over to OpenRouter or DeepInfra, which also serve the model. The thinking settings above are sent to OpenRouter too, with two differences. Sonnet 5.5 cannot stop thinking there, so it thinks at the lowest effort, and none is reported as X-Mapped-Params: reasoning_effort=low. The thinking is shown as reasoning instead of reasoning_content, at the lowest effort too, unless you set include_reasoning: false. With no reasoning_effort, nothing is sent to OpenRouter either, and the model thinks at OpenRouter's own default. If OpenRouter refuses the thinking setting, the request is sent to it once more with reasoning_effort passed on as sent, and the model then thinks at OpenRouter's own default. On DeepInfra the model thinks at DeepInfra's own default (Claude 5.x models think and do not show it), and reasoning_effort is passed on as sent. The estimate from thinking time for a closed stream applies only while Anthropic serves the request. The response headers describe the provider that served it.

Models other than Claude served by OpenAI-compatible providers (OpenRouter, DeepInfra, Together and the like, but not OpenAI itself), and Claude on DeepInfra, receive the value as sent and never trigger an adjustment. Sovereign models served on our own GPUs follow their chat template: the Qwen3.8 family (SovereignEG/Qwen3.8-27B-FP8) accepts low, medium and xhigh, so high is sent as xhigh and minimal as low; none goes through unchanged and turns reasoning off; other sovereign families receive the value as sent. On streaming and non-streaming responses alike, the headers describe the backing that served the request, including after a failover to another backing.

Sampling on Claude Opus 4.7 and later

Claude Opus 4.7 and later Claude models accept only their default sampling: Anthropic refuses a request that sets temperature or top_p to anything but the model's default (1 for temperature). This covers Claude Opus 4.7, Opus 4.8, Opus 5, Opus 5.5, Sonnet 5, Sonnet 5.5, Haiku 5.5, the Fable and Mythos models, and Claude models newer than the gateway's table. While Anthropic serves the request, the gateway leaves both out, the model samples at its defaults, and the response names what was left out: X-Dropped-Params: temperature, or X-Dropped-Params: temperature, top_p when you set both. When reasoning_effort is dropped as well, it is listed first: X-Dropped-Params: reasoning_effort, temperature. GET /v1/models lists these models with capabilities.supports_temperature: false and without temperature, top_p or top_k in supported_parameters.

Claude Opus 4.6, Sonnet 4.6, Haiku 4.5 and older models still receive the value you set. Anthropic accepts only one of the two, so when you set both they receive temperature, and X-Dropped-Params: top_p names the one left out. top_k is not a parameter the gateway recognises, so it never reaches any model; on Claude models served by Anthropic, X-Dropped-Params names it when you set it. After a failover to another provider, temperature and top_p are passed on as sent.

Message roles

RolePurpose
systemSets the behavior of the assistant. Some sovereign models on our own GPUs, such as SovereignEG/Qwen3.8-27B-FP8, accept only one system message, at the start, so for every sovereign model on our own GPUs the system messages at the start are sent as one, joined by a blank line, and a system message later in the conversation is sent in its place as a user message that starts with [system]. Claude models served directly by Anthropic take every system message into one system prompt, wherever it is in the conversation
developerOpenAI's newer name for system. Claude models served directly by Anthropic treat it as system; other models receive it as sent and whether they honour it depends on the model, so use system when in doubt
userThe human's input
assistantThe model's previous response (for multi-turn), including any tool_calls it made
toolThe result of a tool call; requires tool_call_id (see Function Calling)

Example request

from openai import OpenAI
 
client = OpenAI(
    api_key="sk-...",
    base_url="https://backend.sovereigneg.com/v1"
)
 
response = client.chat.completions.create(
    model="gpt-oss-20b",
    messages=[
        {"role": "system", "content": "You are a concise technical writer."},
        {"role": "user", "content": "Explain how transformers work in 3 sentences."}
    ],
    temperature=0.7,
    max_tokens=256
)
 
print(response.choices[0].message.content)

Response

{
  "id": "chatcmpl-abc123",
  "object": "chat.completion",
  "created": 1711000000,
  "model": "<id reported by the serving model>",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Transformers use self-attention mechanisms..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 28,
    "completion_tokens": 65,
    "total_tokens": 93
  }
}

model in the response is the id reported by the provider or engine that served the request. It can differ from the id you sent (for example a vendor-prefixed or dated snapshot name), so do not compare it to your request.

Streaming

Set stream: true to receive tokens as server-sent events. See Streaming for details, including the last chunk of a stream that runs out of credit part-way.

Multi-turn conversation

Pass the full conversation history in the messages array:

response = client.chat.completions.create(
    model="gpt-oss-20b",
    messages=[
        {"role": "system", "content": "You are a helpful math tutor."},
        {"role": "user", "content": "What is 15% of 200?"},
        {"role": "assistant", "content": "15% of 200 is 30."},
        {"role": "user", "content": "And 20% of the same number?"}
    ]
)
Chat Completions | SovereignEG Docs