DeepSeek: Deepseek V4.1 Flash API Reference

Infron provides a unified gateway for text generation, reasoning models, multimodal chat, embeddings, reranking, and batch generation. The LLM gateway is OpenAI-compatible, Anthropic-compatible, and OpenResponses-compatible, so most applications can integrate by changing only the base URL and API key.

Contents

  1. Connection and quickstart
  2. Model capabilities
  3. Routing and enterprise configuration
  4. Agent, framework and tool integrations
  5. Usage and errors

1. Connection and quickstart

Follow Quickstart to create an API key, then obtain a full model ID from the model list. Choose cURL, Python or TypeScript to send your first chat request.

1.1 Full endpoint URLs

CapabilityMethodFull request URL
Chat CompletionsPOSThttps://llm.onerouter.pro/v1/chat/completions
ResponsesPOSThttps://llm.onerouter.pro/v1/responses
Anthropic MessagesPOSThttps://llm.onerouter.pro/v1/messages
Model listGEThttps://llm.onerouter.pro/v1/models
EmbeddingsPOSThttps://llm.onerouter.pro/v1/embeddings
RerankingPOSThttps://llm.onerouter.pro/v1/rerank
BalanceGEThttps://api.onerouter.pro/v1/balance

SDKs append the endpoint path to these Base URLs:

ClientBase URL
OpenAI Python / TypeScript SDKhttps://llm.onerouter.pro/v1
Anthropic SDKhttps://llm.onerouter.pro

For direct HTTP requests, use the address in the “Full request URL” table and set Authorization: Bearer <INFRON_API_KEY>. For SDKs, configure the corresponding Base URL and API key.

1.2 Set environment variables

The quickstarts require Chat Completions support. In other sections, run only the examples for endpoints and features supported by the model.

Replace YOUR_INFRON_API_KEY with your API key and run the command in bash or zsh on macOS / Linux. Use the same terminal for subsequent commands. When deploying, store the key in a server-side environment variable.

export INFRON_API_KEY="YOUR_INFRON_API_KEY"

1.3 cURL quickstart

Run this request to view the JSON response.

curl --request POST "https://llm.onerouter.pro/v1/chat/completions" \
  --header "Authorization: Bearer $INFRON_API_KEY" \
  --header "Content-Type: application/json" \
  --data-binary @- <<JSON
{
  "model": "deepseek/deepseek-v4.1-flash",
  "messages": [
    {"role": "user", "content": "Reply with: Infron connection successful."}
  ],
  "stream": false,
  "usage": {"include": true}
}
JSON

1.4 Python quickstart

Install the dependency with Python 3.9+:

python3 -m pip install openai

Save as quickstart.py:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://llm.onerouter.pro/v1",
    api_key=os.environ["INFRON_API_KEY"],
    timeout=60.0,
    max_retries=0,
)
raw = client.chat.completions.with_raw_response.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{
        "role": "user",
        "content": "Reply with: Infron connection successful.",
    }],
    extra_body={"usage": {"include": True}},
)
response = raw.parse()
print("HTTP", raw.status_code)
print("id:", response.id)
print("model:", response.model)
print("reply:", response.choices[0].message.content)
print("usage:", response.model_dump().get("usage"))

Run:

python3 quickstart.py

The OpenAI SDK examples in section 2 omit client setup. To run one separately, copy the imports and client = OpenAI(...) initialization from this section first.

1.5 TypeScript / Node.js quickstart

Install dependencies in your project directory:

npm install openai
npm install --save-dev typescript @types/node

Save as quickstart.mts:

import OpenAI from "openai";

const apiKey = process.env.INFRON_API_KEY;
if (!apiKey) {
  throw new Error("Set INFRON_API_KEY first.");
}

const client = new OpenAI({
  baseURL: "https://llm.onerouter.pro/v1",
  apiKey,
  timeout: 60_000,
  maxRetries: 0,
});
const body = {
  model: "deepseek/deepseek-v4.1-flash",
  messages: [{
    role: "user" as const,
    content: "Reply with: Infron connection successful.",
  }],
  usage: { include: true },
};
const { data: result, response } = await client.chat.completions
  .create(body)
  .withResponse();
console.log("HTTP", response.status);
console.log("id:", result.id);
console.log("model:", result.model);
console.log("reply:", result.choices[0]?.message.content);
console.log("usage:", result.usage);

Compile quickstart.mts to JavaScript, then run it with Node.js:

npx tsc quickstart.mts --module NodeNext --target ES2022 --types node --outDir dist
node dist/quickstart.mjs

1.6 Check the result

For this example, HTTP 200 with a model reply confirms a successful chat request. In cURL, read choices[0].message.content. Python and TypeScript print the reply, response ID, returned model ID and usage. The prompt asks for Infron connection successful., but the model may use different wording.

To check service connectivity without generating a reply, query the model list:

curl "https://llm.onerouter.pro/v1/models" \
  --header "Authorization: Bearer $INFRON_API_KEY"

A successful model-list request only confirms access to that endpoint. Send a chat request above to confirm that the API key can use the selected model. For 401, check the key; for 402, check balance or budgets; for 429, check rate limits. See error handling.

2. Model capabilities

CapabilityMethod and path
Chat CompletionsPOST /v1/chat/completions
ResponsesPOST /v1/responses
Anthropic MessagesPOST /v1/messages
EmbeddingsPOST /v1/embeddings
RerankPOST /v1/rerank

Required and common optional fields are grouped by endpoint below. Models using the same protocol may support different features; check the model and provider documentation. Dotted names denote nested paths: usage.include means {"usage": {"include": true}}.

Chat Completions

  • Required: model, messages
  • Optional · Sampling: temperature, top_p, frequency_penalty, presence_penalty, seed
  • Optional · Output: max_completion_tokens, max_tokens, stop, response_format
  • Optional · Tools: tools, tool_choice, parallel_tool_calls
  • Optional · Reasoning: reasoning
  • Optional · Probabilities: logprobs, top_logprobs, logit_bias
  • Optional · Streaming: stream, stream_options.include_usage
  • Optional · Gateway: provider, preset, usage.include

Responses

  • Required: model, input
  • Optional · Input and metadata: instructions, metadata
  • Optional · Output: max_output_tokens, text.format, text.verbosity, truncation
  • Optional · Tools: tools, tool_choice, parallel_tool_calls
  • Optional · Reasoning and returned data: reasoning, include, top_logprobs
  • Optional · Streaming: stream
  • Optional · Gateway: provider, preset, usage.include

Anthropic Messages

  • Required: model, messages, max_tokens
  • Optional · Input and metadata: system, metadata
  • Optional · Sampling and stopping: temperature, top_p, top_k, stop_sequences
  • Optional · Tools: tools, tool_choice
  • Optional · Reasoning and output: thinking, output_config
  • Optional · Caching and streaming: cache_control, stream
  • Optional · Gateway: provider, usage.include

Embeddings

  • Required: model, input
  • Optional · Encoding: encoding_format

Rerank

  • Required: model, query, documents
  • Optional · Result count: top_n

Common field usage

FieldHow to use it
messagesMessage array. Ordinary text messages include role and content; see section 2.4 for tool-call messages. Chat places system instructions in messages; Anthropic Messages uses top-level system
inputResponses accepts a string or input-item array; Embeddings commonly takes a string or string array
max_completion_tokens / max_tokensChoose the field supported by the Chat model to set the output token limit; do not send both. max_completion_tokens includes reasoning tokens. Responses uses max_output_tokens; Messages requires max_tokens
temperature / top_p / top_kSampling controls; usually adjust one. Supported fields and ranges depend on the model
stop / stop_sequencesStop sequences for Chat / Messages, respectively; some reasoning models do not support them
logprobs / top_logprobsChat output-token log probabilities; enable logprobs and set top_logprobs for candidate probabilities
seedSet a sampling seed where supported to improve reproducibility; identical seeds do not guarantee identical replies
encoding_formatEmbeddings encoding: float or base64; the vector-reading example below expects float arrays
top_nReturn the top N reranked results; use a positive integer no larger than the document count. documents is the array of texts to rank

Pass SDK-declared arguments directly to the Python SDK. Use extra_body for extensions supported by the API but absent from the SDK. In direct HTTP requests, place these fields at the top level of the body without an extra_body wrapper. See section 3 for provider fields and calls.

2.1 Streaming

stream = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Explain vector search briefly."}],
    stream=True,
    stream_options={"include_usage": True},
    extra_body={"usage": {"include": True}},
)
try:
    for chunk in stream:
        if chunk.choices:
            text = chunk.choices[0].delta.content
            if text:
                print(text, end="", flush=True)
        if chunk.usage is not None:
            print("\nusage:", chunk.usage.model_dump())
finally:
    stream.close()

Usage events may have an empty choices array; check before reading it. Custom SSE parsers should ignore keepalive comments starting with :. Tool arguments may arrive in multiple chunks; assemble them before parsing and execution.

2.2 Responses

response = client.responses.create(
    model="deepseek/deepseek-v4.1-flash",
    input=[{"role": "user", "content": "Explain a unified inference gateway."}],
    max_output_tokens=300,
    extra_body={"usage": {"include": True}},
)
print(response.output_text)

Common request fields are listed below. Tool calling, reasoning and structured output require model support.

FieldHow to set it
model / inputModel ID; input may be a string or an array of Responses input items
instructionsSystem/developer instruction string
max_output_tokens / streamOutput token limit; set stream: true for streamed events
tools / tool_choiceTool definitions and selection; return function results as function_call_output
parallel_tool_callsAllow multiple tool calls in one generation
text.formatStructured output format; use type: "json_schema" for JSON Schema
reasoningReasoning settings, such as {"effort": "low"}
text.verbosityOutput detail level, where supported by the model
metadataBusiness labels attached to the request; these do not set team, access or routing rules
truncationInput truncation policy when the context is too long; set as supported by the API
include / top_logprobsRequest additional returned data and candidate token probabilities where supported
provider / usage.includeProvider routing; set usage.include: true for usage reporting

In the Python SDK, pass provider, preset and usage through extra_body; pass other supported fields as SDK arguments.

For continued conversations, include the necessary history and tool results in input. Use persistent state, hosted tools or WebSockets only when the target endpoint explicitly supports them.

2.3 Anthropic Messages

Run python3 -m pip install anthropic. The model must support the Messages API; set base_url to the root address without /v1.

import os
from anthropic import Anthropic

anthropic_client = Anthropic(
    base_url="https://llm.onerouter.pro",
    api_key=os.environ["INFRON_API_KEY"],
    timeout=60.0,
)
response = anthropic_client.messages.create(
    model="deepseek/deepseek-v4.1-flash",
    max_tokens=512,
    messages=[{"role": "user", "content": "Explain tool calling briefly."}],
)
for block in response.content:
    if block.type == "text":
        print(block.text)

2.4 Tool calling

Declare functions in tools. The model returns function names and arguments; your application executes the functions and sends the results back for the next model response. This example reads a local demonstration record.

import json

records = {"demo-001": {"status": "ready", "items": 3}}
tools = [{
    "type": "function",
    "function": {
        "name": "lookup_record",
        "description": "Read a demonstration record by ID.",
        "parameters": {
            "type": "object",
            "properties": {"record_id": {"type": "string"}},
            "required": ["record_id"],
            "additionalProperties": False,
        },
    },
}]
messages = [{"role": "user", "content": "Look up demo-001 and summarize it."}]
for _ in range(6):
    result = client.chat.completions.create(
        model="deepseek/deepseek-v4.1-flash",
        messages=messages,
        tools=tools,
        tool_choice="auto",
    )
    message = result.choices[0].message
    if not message.tool_calls:
        print(message.content)
        break
    # Retain model-specific fields returned with the assistant turn.
    messages.append(message.model_dump(exclude_none=True))
    for call in message.tool_calls:
        try:
            if call.function.name != "lookup_record":
                raise ValueError("Unknown tool")
            args = json.loads(call.function.arguments)
            if not isinstance(args, dict) or set(args) != {"record_id"}:
                raise ValueError("Expected only record_id")
            if not isinstance(args["record_id"], str):
                raise ValueError("record_id must be a string")
            output = records.get(args["record_id"], {"error": "not_found"})
        except (ValueError, TypeError) as exc:
            output = {"error": str(exc)}
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(output),
        })
else:
    raise RuntimeError("Tool round limit reached")
ProtocolTool result format
Chat Completionsrole: tool + tool_call_id
Responsestype: function_call_output + call_id + output
Messagestype: tool_result + tool_use_id in user content blocks

When returning results, retain the corresponding assistant tool-call message and any returned reasoning or signature fields. Tools that perform writes should check application permissions and prevent duplicate writes.

2.5 Structured output

Use Structured Outputs to extract fields or generate data following a JSON Schema. The model must support this feature. Chat Completions uses response_format; Responses uses text.format.

Set these fields inside response_format in a Chat request:

FieldHow to use it
typeSet to "json_schema"
json_schema.nameSchema name, such as "city_result"
json_schema.strictSet to true to enforce the schema
json_schema.schemaDefine the object, properties and field types; use description to explain each field
json_schema.schema.requiredList the fields that must be returned
json_schema.schema.additionalPropertiesSet to false to disallow undeclared fields

Complete Chat request body:

{
  "model": "deepseek/deepseek-v4.1-flash",
  "messages": [{"role": "user", "content": "Extract the city from: I live in Paris."}],
  "response_format": {
    "type": "json_schema",
    "json_schema": {
      "name": "city_result",
      "strict": true,
      "schema": {
        "type": "object",
        "properties": {
          "city": {"type": "string", "description": "City named in the input text."}
        },
        "required": ["city"],
        "additionalProperties": false
      }
    }
  }
}

Read JSON text from choices[0].message.content, then parse it with json.loads(...) or an equivalent parser. This example extracts {"city": "Paris"}. With the OpenAI Python SDK, pass response_format as a regular argument.

For streaming, add stream: true, assemble delta.content in order, and parse the complete result as JSON. Check for refusal or truncation before parsing. If the model does not support the feature or the schema is invalid, inspect the error and adjust the request. A schema constrains the format; the application must still validate the business content.

2.6 Reasoning controls

Use Reasoning & Thinking to set reasoning effort or a reasoning token limit. Chat Completions accepts a unified reasoning field, which Infron converts to the provider’s parameters.

SettingHow to use it
Omit reasoningKeep the provider defaults; omission does not mean reasoning is disabled
reasoning.effortOptions: xhigh, high, medium, low, minimal, none; supported values depend on the model. Use none only where disabling reasoning is supported
reasoning.max_tokensSet an upper limit for reasoning tokens, not an exact consumption target; requires model support

Choose either effort or max_tokens. In HTTP requests, put reasoning at the top level of the body. In the OpenAI Python SDK, pass it through extra_body. This example reuses client from section 1.4:

response = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Is 91 prime? Explain briefly."}],
    extra_body={
        "reasoning": {"effort": "low"},
        "usage": {"include": True},
    },
)
message = response.choices[0].message.model_dump()
print("reply:", message.get("content"))
print("reasoning:", message.get("reasoning") or message.get("reasoning_content"))
print("reasoning_details:", message.get("reasoning_details"))
print("usage:", response.model_dump().get("usage"))

To limit reasoning by token count, replace the reasoning configuration above with:

{"reasoning": {"max_tokens": 2000}}

To disable reasoning where supported, replace it with:

{"reasoning": {"effort": "none"}}

Reasoning information may appear in message.reasoning, message.reasoning_content or message.reasoning_details. Some models do not return readable reasoning text. For streaming, read the corresponding fields from delta while also handling delta.content; skip message access when choices is empty.

Reasoning tokens count toward output usage and charges. When returned, read their count from usage.completion_tokens_details.reasoning_tokens. Leave room in the output limit for both reasoning and the final reply.

Anthropic Messages uses its native thinking field. This request requires support for manual thinking; max_tokens must exceed budget_tokens:

{
  "model": "deepseek/deepseek-v4.1-flash",
  "max_tokens": 4096,
  "thinking": {"type": "enabled", "budget_tokens": 1024},
  "messages": [{"role": "user", "content": "Is 91 prime? Explain briefly."}]
}

2.7 Image, PDF, audio and video input

These are Chat Completions content-block examples, not a complete request. Add the blocks required by the task and supported by the model to a user message’s content array, alongside a type: "text" instruction. Replace sample URLs and Base64 placeholders with real assets.

[
  {"type": "image_url", "image_url": {"url": "https://example.com/image.png"}},
  {"type": "file", "file": {"filename": "document.pdf", "file_data": "https://example.com/document.pdf"}},
  {"type": "input_audio", "input_audio": {"data": "REPLACE_WITH_BASE64_AUDIO", "format": "wav"}},
  {"type": "video_url", "video_url": {"url": "https://example.com/video.mp4"}}
]

Check the model documentation for file formats, size limits, and support for remote URLs or Base64 data URLs. input_audio.data takes Base64 without a data URL prefix. Responses and Anthropic Messages use their own content-block formats.

2.8 Embeddings, reranking and RAG

The two examples below require an embedding model and a reranking model, respectively. A basic RAG pipeline is: chunk documents → vector retrieval → rerank → generate an answer. Use the same embedding model and dimensions for document indexing and query embeddings.

embedded = client.embeddings.create(
    model="deepseek/deepseek-v4.1-flash",
    input=["Infron connects applications to model providers.", "Paris is in France."],
    encoding_format="float",
)
vectors = [item.embedding for item in sorted(embedded.data, key=lambda x: x.index)]
print("vectors:", len(vectors), "dimensions:", len(vectors[0]))

The reranking example uses HTTP. Run python3 -m pip install httpx first.

import os
import httpx

with httpx.Client(timeout=60.0, headers={
    "Authorization": f"Bearer {os.environ['INFRON_API_KEY']}",
}) as http:
    result = http.post("https://llm.onerouter.pro/v1/rerank", json={
        "model": "deepseek/deepseek-v4.1-flash",
        "query": "Which city is in France?",
        "documents": ["Paris is in France.", "Tokyo is in Japan."],
        "top_n": 1,
    })
    result.raise_for_status()
    print(result.json())

3. Routing and enterprise configuration

model selects a model; provider selects serving providers. Omitting provider uses default routing. For HTTP, put routing fields in the request body; with the OpenAI Python SDK, pass provider and usage through extra_body.

Use INFRON_API_KEY from section 1. Set the variable below when selecting a provider. Replace the example deepinfra with a provider slug supported by the current model.

export INFRON_PROVIDER="deepinfra"

3.1 cURL: sort by price

curl --request POST "https://llm.onerouter.pro/v1/chat/completions" \
  -H "Authorization: Bearer $INFRON_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<EOF
{
  "model": "deepseek/deepseek-v4.1-flash",
  "messages": [{"role": "user", "content": "Explain provider routing briefly."}],
  "provider": {"sort": "price", "allow_fallbacks": true},
  "usage": {"include": true}
}
EOF

3.2 Python: examples for each parameter

Run python3 -m pip install openai. Place the initialization below and the desired route(...) example in the same Python file. Each call to route(...) sends one model request.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://llm.onerouter.pro/v1",
    api_key=os.environ["INFRON_API_KEY"],
    timeout=60.0,
    max_retries=0,
)

def route(provider, *, include_usage=True):
    response = client.chat.completions.create(
        model="deepseek/deepseek-v4.1-flash",
        messages=[{"role": "user", "content": "Explain provider routing briefly."}],
        extra_body={"provider": provider, "usage": {"include": include_usage}},
    )
    print(response.choices[0].message.content)
    print(response.model_dump())
    return response

provider.sort

price prioritizes lower prices, latency lower latency, and throughput higher throughput. Run the call for your preferred option:

route({"sort": "price"})
route({"sort": "latency"})
route({"sort": "throughput"})

provider.order

Set provider preference order; append other provider slugs supported by the model as needed.

route({"order": [os.environ["INFRON_PROVIDER"]], "allow_fallbacks": True})

provider.only

Allow only the specified providers; disable fallback for a strict restriction.

route({"only": [os.environ["INFRON_PROVIDER"]], "allow_fallbacks": False})

provider.ignore

Exclude the specified providers; the model must have another eligible provider.

route({"ignore": [os.environ["INFRON_PROVIDER"]]})

provider.allowfallbacks

In these examples, True allows another eligible provider to be tried after the specified provider fails. False returns an error after that failure.

route({"order": [os.environ["INFRON_PROVIDER"]], "allow_fallbacks": True})
route({"order": [os.environ["INFRON_PROVIDER"]], "allow_fallbacks": False})

provider.preferredminthroughput

Prefer providers whose throughput reaches the specified value, in tokens per second. A number applies to p50 (the median); an object can specify another percentile such as p90.

route({"preferred_min_throughput": 50})
route({"preferred_min_throughput": {"p90": 50}})

provider.preferredmaxlatency

Prefer providers whose latency stays within the specified value, in seconds. A number applies to p50 (the median); an object can specify another percentile such as p90.

route({"preferred_max_latency": 3})
route({"preferred_max_latency": {"p90": 3}})

Performance thresholds support p50, p75, p90 and p99. Providers that miss a threshold are deprioritized, not excluded. These settings do not guarantee performance for an individual request.

provider.datacollection

deny excludes providers that may store request data; allow lets those providers participate in routing.

route({"data_collection": "deny"})

provider.zdr

Select only endpoints tagged for zero data retention.

route({"zdr": True})

provider.servicetier

standard uses the standard tier, flex prioritizes lower cost, and priority prioritizes lower latency. Run the call for your preferred option:

route({"service_tier": "standard"})
route({"service_tier": "flex"})
route({"service_tier": "priority"})

Flex or Priority may fall back to Standard when unavailable; record charges against the tier actually served.

provider.quantizations

Filter quantization formats, such as FP8 only; the model must have a matching endpoint.

route({"quantizations": ["fp8"]})

usage.include

True requests usage information; False disables that option. The function argument include_usage maps to the request field usage.include. Available details depend on the API response.

route({}, include_usage=True)
route({}, include_usage=False)

Routing reference

3.3 Prompt caching

Select a model supporting explicit caching and save the full reusable policy document as company-policy.txt. Its length must meet the model's minimum cache requirement.

export INFRON_CACHE_FILE="./company-policy.txt"

Reuse the client initialization from section 3.2 and ensure company-policy.txt exists. Define the function below, then add one of the cached_chat(...) calls.

from pathlib import Path

policy = Path(os.environ["INFRON_CACHE_FILE"]).read_text(encoding="utf-8")

def cached_chat(cache_control):
    response = client.chat.completions.create(
        model="deepseek/deepseek-v4.1-flash",
        messages=[
            {"role": "system", "content": [{
                "type": "text",
                "text": policy,
                "cache_control": cache_control,
            }]},
            {"role": "user", "content": "Summarize the approval process in this policy."},
        ],
        extra_body={"usage": {"include": True}},
    )
    print(response.choices[0].message.content)
    print(response.model_dump().get("usage"))
    return response

cachecontrol.type

Add cache_control: {"type": "ephemeral"} to a content block. The cached prefix runs from the start of the prompt through the end of that block.

cached_chat({"type": "ephemeral"})

cachecontrol.ttl

Set ttl: "1h" to specify the cache lifetime on a Claude model that supports one-hour caching.

cached_chat({"type": "ephemeral", "ttl": "1h"})

Keep tools, system instructions and the document prefix identical on subsequent requests; change only the final question. Inspect returned cache read/write tokens to check hits; an initial write is not a hit. Sticky routing improves reuse without guaranteeing hits. Prompt caching

4. Agent, framework and tool integrations

Browse integration guides by use case. See the integration overview for more agents, memory and evaluation tools.

4.1 Coding and desktop agents

  • Claude Code / Claude Agent SDK: Connect coding assistants and Claude Agent SDK.
  • Codex CLI: Connect the terminal coding agent through Responses.
  • OpenCode: Configure Infron as an OpenCode model provider.
  • OpenClaw: Configure Infron models for personal assistants and automation.
  • OpenWork: Connect desktop agents and OpenCode workspaces.
  • Hermes Agent: Connect models and tool calling for the terminal agent.

4.2 SDKs, agent frameworks and application development

4.3 Workflows and observability

  • n8n: Call Infron models in visual automation workflows.
  • Langfuse: Record and trace Infron model calls.

5. Usage and errors

Add "usage": {"include": true} to Chat requests. For streaming, also set "stream_options": {"include_usage": true}. Record response ID, resolved model, returned provider, token usage, cost and latency.

Read usage according to the API protocol. Record cache, reasoning and cost details when present; do not treat missing fields as zero.

Response fieldPurpose
usage.prompt_tokens / usage.input_tokensInput tokens for Chat / Responses, respectively
usage.completion_tokens / usage.output_tokensOutput tokens for Chat / Responses, respectively
usage.total_tokensTotal tokens
usage.prompt_tokens_details.cached_tokensCached prompt tokens in Chat
usage.prompt_tokens_details.cache_write_tokensCache-write tokens in Chat
usage.completion_tokens_details.reasoning_tokensReasoning tokens in Chat
cost / cost_detailsCost and breakdown; preserve the original structure returned by each API

Query balance:

curl "https://api.onerouter.pro/v1/balance" \
  -H "Authorization: Bearer $INFRON_API_KEY"

Read the HTTP status first, then the error object. error.code may differ from the HTTP status.

Error fieldPurpose
error.messageError description
error.type / error.codeError category and API error code; retain their original values
error.paramRelated request parameter; may be null or absent
ErrorAction
400 / 422Check model ID, protocol, field types and model capabilities
401Check key, authentication headers and loaded environment variables
402Check balance, budgets and quota
403Check model, team and key permissions
429Check RPM, TPM and concurrency limits; honor Retry-After when present and reduce concurrency
502 / 503Check provider availability and routing constraints; use bounded retries
TimeoutSet connection, read and overall request timeouts

Allocate keys, budgets and rate limits by team and application. Use exponential backoff with jitter for retryable failures; avoid multiplying retries across SDKs, gateways and workflows.