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
- Connection and quickstart
- Model capabilities
- Routing and enterprise configuration
- Agent, framework and tool integrations
- 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
| Capability | Method | Full request URL |
|---|---|---|
| Chat Completions | POST | https://llm.onerouter.pro/v1/chat/completions |
| Responses | POST | https://llm.onerouter.pro/v1/responses |
| Anthropic Messages | POST | https://llm.onerouter.pro/v1/messages |
| Model list | GET | https://llm.onerouter.pro/v1/models |
| Embeddings | POST | https://llm.onerouter.pro/v1/embeddings |
| Reranking | POST | https://llm.onerouter.pro/v1/rerank |
| Balance | GET | https://api.onerouter.pro/v1/balance |
SDKs append the endpoint path to these Base URLs:
| Client | Base URL |
|---|---|
| OpenAI Python / TypeScript SDK | https://llm.onerouter.pro/v1 |
| Anthropic SDK | https://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
| Capability | Method and path |
|---|---|
| Chat Completions | POST /v1/chat/completions |
| Responses | POST /v1/responses |
| Anthropic Messages | POST /v1/messages |
| Embeddings | POST /v1/embeddings |
| Rerank | POST /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
| Field | How to use it |
|---|---|
messages | Message 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 |
input | Responses accepts a string or input-item array; Embeddings commonly takes a string or string array |
max_completion_tokens / max_tokens | Choose 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_k | Sampling controls; usually adjust one. Supported fields and ranges depend on the model |
stop / stop_sequences | Stop sequences for Chat / Messages, respectively; some reasoning models do not support them |
logprobs / top_logprobs | Chat output-token log probabilities; enable logprobs and set top_logprobs for candidate probabilities |
seed | Set a sampling seed where supported to improve reproducibility; identical seeds do not guarantee identical replies |
encoding_format | Embeddings encoding: float or base64; the vector-reading example below expects float arrays |
top_n | Return 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.
| Field | How to set it |
|---|---|
model / input | Model ID; input may be a string or an array of Responses input items |
instructions | System/developer instruction string |
max_output_tokens / stream | Output token limit; set stream: true for streamed events |
tools / tool_choice | Tool definitions and selection; return function results as function_call_output |
parallel_tool_calls | Allow multiple tool calls in one generation |
text.format | Structured output format; use type: "json_schema" for JSON Schema |
reasoning | Reasoning settings, such as {"effort": "low"} |
text.verbosity | Output detail level, where supported by the model |
metadata | Business labels attached to the request; these do not set team, access or routing rules |
truncation | Input truncation policy when the context is too long; set as supported by the API |
include / top_logprobs | Request additional returned data and candidate token probabilities where supported |
provider / usage.include | Provider 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")
| Protocol | Tool result format |
|---|---|
| Chat Completions | role: tool + tool_call_id |
| Responses | type: function_call_output + call_id + output |
| Messages | type: 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:
| Field | How to use it |
|---|---|
type | Set to "json_schema" |
json_schema.name | Schema name, such as "city_result" |
json_schema.strict | Set to true to enforce the schema |
json_schema.schema | Define the object, properties and field types; use description to explain each field |
json_schema.schema.required | List the fields that must be returned |
json_schema.schema.additionalProperties | Set 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.
| Setting | How to use it |
|---|---|
Omit reasoning | Keep the provider defaults; omission does not mean reasoning is disabled |
reasoning.effort | Options: xhigh, high, medium, low, minimal, none; supported values depend on the model. Use none only where disabling reasoning is supported |
reasoning.max_tokens | Set 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)
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
- OpenAI SDK: Call Infron-compatible APIs with OpenAI clients.
- Anthropic SDK: Call the Messages API with Anthropic clients.
- OpenAI Agents SDK: Build agents and tool workflows using Infron models.
- LangChain / LangGraph: Connect model chains, agents and workflows.
- PydanticAI: Connect typed agents and structured outputs.
- Vercel AI SDK: Add generation, streaming and tool calls to TypeScript applications.
- LiteLLM: Connect through a unified model client or proxy.
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 field | Purpose |
|---|---|
usage.prompt_tokens / usage.input_tokens | Input tokens for Chat / Responses, respectively |
usage.completion_tokens / usage.output_tokens | Output tokens for Chat / Responses, respectively |
usage.total_tokens | Total tokens |
usage.prompt_tokens_details.cached_tokens | Cached prompt tokens in Chat |
usage.prompt_tokens_details.cache_write_tokens | Cache-write tokens in Chat |
usage.completion_tokens_details.reasoning_tokens | Reasoning tokens in Chat |
cost / cost_details | Cost 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 field | Purpose |
|---|---|
error.message | Error description |
error.type / error.code | Error category and API error code; retain their original values |
error.param | Related request parameter; may be null or absent |
| Error | Action |
|---|---|
| 400 / 422 | Check model ID, protocol, field types and model capabilities |
| 401 | Check key, authentication headers and loaded environment variables |
| 402 | Check balance, budgets and quota |
| 403 | Check model, team and key permissions |
| 429 | Check RPM, TPM and concurrency limits; honor Retry-After when present and reduce concurrency |
| 502 / 503 | Check provider availability and routing constraints; use bounded retries |
| Timeout | Set 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.