Inference API Reference
OpenAI-compatible API for running AI models. Drop-in replacement for any OpenAI SDK.
Base URL
https://api.inferbase.ai/api/v1/inferenceAlso served at
https://api.inferbase.ai/v1The short form exists for SDKs that expect a /v1 base. Both paths serve the same endpoints with the same auth, limits and timeouts; pick whichever your client assumes and do not mix them in one integration.
Anthropic clients: point ANTHROPIC_BASE_URL at https://api.inferbase.ai and POST /v1/messages works as it does against Anthropic, including streaming, images and the full tool loop (tool_use and tool_result blocks both ways, streamed tool calls as input_json_delta events, cumulative usage with the cache split on message_delta). model takes the same values as the OpenAI surface, "auto" included, so an Anthropic SDK can route. Not translated yet: thinking, documentblocks and images inside a tool result; each is refused with a 400 naming the field rather than dropped. Errors use Anthropic's {"type": "error", "error": {...}, "request_id"} envelope on that path, with 400 for a malformed request as Anthropic does.
Authentication
Most inference endpoints require authentication (the exceptions are marked below: the model listing, the health check and the routing preview are open). You can use either an API key (for programmatic access) or a JWT token (for browser-based access).
API Key (recommended for code)
API keys start with inf_ and are passed in the Authorization header.
Authorization: Bearer inf_your_api_key_hereJWT Token (browser sessions)
If you're already logged into Inferbase, the JWT cookie is sent automatically. No additional setup needed for dashboard interactions.
Chat Completions
/chat/completionsAPI Key or JWTCreate a chat completion. Supports streaming and non-streaming responses.
Request Body
messagesarray, required- Array of message objects with role and content. Content may be a string or an array of text / image_url blocks (vision). Image requests work with a pin or with "auto": routing serves only image-capable models and picks among them on your optimization axisstreamboolean, optional- Enable SSE streaming (default: false)temperaturenumber, optional- Sampling temperature 0-2 (default: 1.0)max_tokensnumber, optional- Maximum tokens to generate. Defaults to 4096if omitted, so long-form output is truncated with finish_reason "length" unless you raise it.seednumber, optional- Best-effort determinism, forwarded to the vendorpresence_penaltynumber, optional- -2.0 to 2.0. frequency_penalty, logit_bias, logprobs, top_logprobs, user and parallel_tool_calls are accepted and forwarded the same way; logprobs come back on each choice. Anthropic-served models have no equivalent for seed, the penalties, logit_bias, logprobs or a message name: a request pinned to one is refused with a 400 naming the parameter, and a routed request that lands on one lists what was not forwarded in usage.dropped_params, so a 200 never hides a dropped knobstream_optionsobject, optional- {"include_usage": true} ends the stream with a standards-shaped chunk carrying usage and an empty choices arraynnumber, optional- Only 1 is supported. A routed request picks one model for one answer, so n > 1 is a 422 rather than a silently truncated responsetoolsarray, optional- Tools the model may call (OpenAI shape), with tool_choice forwarded to the provider. Works with "auto": routing is limited to models with verified tool support and measured tool-use quality, and the served model is disclosed. With a pinned model or a custom routing.model_pool the pool is walked in your stated order over its tool-capable models insteadresponse_formatobject, optional- Structured output: {"type": "json_object"} for strict JSON (your prompt must also ask for JSON), or json_schema forwarded to the provider. Routing serves only models with verified structured-output support and ranks them by measured instruction-following qualitycurl -X POST https://api.inferbase.ai/api/v1/inference/chat/completions \
-H "Authorization: Bearer inf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "zai-org/GLM-4.7-Flash",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is machine learning?"}
],
"temperature": 0.7,
"max_tokens": 256
}'Response
{
"id": "req-9f2c1e...",
"object": "chat.completion",
"created": 1712345678,
"model": "zai-org/GLM-4.7-Flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Machine learning is a subset of artificial intelligence..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 128,
"total_tokens": 152
}
}Embeddings
OpenAI-compatible embeddings from the served embedding catalog. Embeddings are pinned-model only: switching embedding models between requests breaks your vector index's consistency, so there is no "auto" here. Billed on input tokens.
curl -X POST https://api.inferbase.ai/api/v1/inference/embeddings \
-H "Authorization: Bearer inf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "Qwen/Qwen3-Embedding-4B",
"input": ["first text to embed", "second text to embed"]
}'Response follows the OpenAI shape: data carries one embedding vector per input, in input order, with input-token usage. dimensions and user are forwarded to the vendor when set; unknown fields are rejected with a 422, as on chat completions.
InferRoute: Smart Model Routing
InferRoute is the classification and scoring engine behind smart model routing. When you set model: "auto", InferRoute analyzes the prompt for task type and complexity, scores each model in your pool on fit, cost, and latency, and routes the request to the highest-ranked option. The model pool and optimization mode are configured on your API key in the dashboard, so individual requests require no additional parameters.
How it works
- Create an API key and select which models to include in the pool
- Choose an optimization mode: Balanced, Quality, Cost, or Speed (API values
balanced,quality,cost,latency) - Send requests with
model: "auto" - InferRoute classifies the prompt by task type and complexity, then selects the highest-scoring model
curl -X POST https://api.inferbase.ai/api/v1/inference/chat/completions \
-H "Authorization: Bearer inf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "auto",
"messages": [{"role": "user", "content": "Write a Python function to sort a list"}]
}'Per-request overrides
The key-level defaults apply to every request automatically. To override them for a specific call, pass a routing object in the request body.
routing.model_poolarray, optional- Restrict routing to these model IDsrouting.sessionstring, optional- Your identifier for a conversation (1-128 printable characters, no spaces). Turns that share it stay on the model that already holds the conversation, so the provider's prompt cache stays warm and a tool loop never changes model mid-flight. Also accepted as the X-Inferbase-Session header (the body wins if both are sent), which is how an Anthropic SDK passes it. Without one, turns are recognised by their shared opening: system prompt and first user messagerouting.session_affinityboolean, default true- Whether Auto keeps a conversation where it is. A turn leaves its model only when that model can no longer serve the request, or when the fresh pick beats it by more than the mode's own noise band (cost mode counts the warm cache before comparing). The routing event says session.stayed and why. Set false to route every turn independentlyrouting.require_prompt_cacheboolean, default false- Serve only on a provider that caches prompt prefixes. Without it, a prompt that carries cache_control breakpoints already prefers such a provider whenever one sits within the routing band (a real quality or price lead still wins); with it, a pool where nothing caches is refused with a 503 that says so. The routing event reports cache_fit.satisfied and how the chosen provider caches; under zero retention the markers are never forwarded and the event says the intent was suppressedrouting.scopestring, optional- Whose models Auto may pick from: "inferbase" (managed catalog, default), "keys" (only your project's provider keys), or "all" (both; a model reachable both ways runs on your key). Overrides the API key's auto scope; ignored with model_poolrouting.optimizestring, optional- "balanced", "quality", "cost", or "latency"routing.taskstring, optional- Override the detected task family. One of: coding, math, knowledge_qa, analysis, creative_writing, summarisation, translation, general. An unrecognised value is IGNORED rather than rejected, and a valid override also fixes complexity at the neutral 0.5, since we are no longer reading the prompt for it.curl -X POST https://api.inferbase.ai/api/v1/inference/chat/completions \
-H "Authorization: Bearer inf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "auto",
"messages": [{"role": "user", "content": "Analyze this contract..."}],
"routing": {
"optimize": "quality",
"model_pool": ["zai-org/GLM-4.7-Flash", "openai/gpt-oss-120b"]
}
}'Streaming routing event
When streaming is enabled with smart routing, the first SSE event contains the routing decision before any content tokens are sent:
data: {"object": "routing", "task": "code_generation", "complexity": "simple", "decisiveness": 0.95, "model": "zai-org/GLM-4.7-Flash", "routing_time_ms": 112}routing_time_ms is the time spent selecting the model, measured per request and reported on every routed response. It scales with prompt length, so read the value your own traffic returns rather than treating the figure above as a guarantee.
Auditing Routing Decisions
Every routed request writes a persistent decision record: what the classifier saw, which models qualified, what was picked over what, and how clear-cut the pick was. The record is yours to query, so routing never has to be taken on faith. There are three ways to read it.
1. Inline, on streaming responses
The routing SSE event above delivers the decision before the first content token. Standard OpenAI SDKs skip events they do not recognize, so read the raw stream if you want it in-band.
2. By request ID, after the fact
Every chat completion response carries a request ID in its id field (req-...). Log it alongside your own request records, then fetch the full decision whenever you need it, with the same API key.
/routing-decisions/{request_id}API Key or JWTThe persisted routing decision for one request: classification, eligible pool, fallback chain, decisiveness, and the per-step eligibility trail.
{
"request_id": "req-9f2c41d8a6b34e17",
"routing_mode": "balanced",
"classifier_task_family": "code_generation",
"classifier_complexity": 0.41,
"eligibility_pool_size": 12,
"final_disposition": "served",
"decisiveness": 0.73,
"forced_single": false,
"chain_attempted": ["<route-id-1>", "<route-id-2>", "<route-id-3>"],
"route_displays": {"<route-id-1>": "GLM-4.7-Flash", "<route-id-2>": "gpt-oss-120b"},
"filter_trail": [
{"step": "pool_loaded", "in": 20, "out": 20},
{"step": "context_fit", "in": 20, "out": 16},
{"step": "preset_eligibility", "in": 16, "out": 12, "preset": "standard"},
{"step": "chain", "in": 12, "out": 3}
]
}decisiveness- The winner's normalized margin over the runner-up. Null when only one model qualified; forced_single marks that case, so a forced pick never masquerades as a decisive win.chain_attempted- Routes in fallback order; the first is the pick. route_displays maps each ID to its catalog model name.filter_trail- How the candidate pool narrowed at each stage, from every servable route down to the final chain.3. In the dashboard
On the Usage page, any smart-routed request in the activity log expands to the same record, rendered with model names, so a human can review routing without touching the API.
Models
/modelsNoneList all models available for inference. The first entry is the virtual model "auto", so smart routing is selectable in any OpenAI-compatible client that builds its model picker from this endpoint.
{
"object": "list",
"data": [
{"id": "auto", "object": "model", "owned_by": "inferbase"},
{"id": "zai-org/GLM-4.7-Flash", "object": "model", "owned_by": "inferbase"},
{"id": "openai/gpt-oss-120b", "object": "model", "owned_by": "inferbase"}
]
}/models/{model_id}/healthNoneReachability of the vendor that serves this model. It does NOT detect a cold model: the check is a liveness probe against the vendor's API, so a warm and a cold model both report ready. Polling it will not avoid a cold start.
{"model": "zai-org/GLM-4.7-Flash", "status": "ready"}
// status: "ready" | "loading" | "unavailable"
// "loading" means the vendor's own API is not answering, not that the model is warming up.API Keys
API keys carry routing configuration (model pool and optimization mode) so your app does not need to send these on every request. Manage keys in the dashboard or via these endpoints. Note that creating, updating and revoking a key require a signed-in session (JWT): an inf_ key cannot manage keys, so that a leaked key cannot mint another one or revoke yours. Listing works with either.
/keysJWT onlyCreate a new API key with optional model pool and optimization mode. The raw key is returned once.
/keysAPI Key or JWTList your API keys with routing config (prefixes only, not raw keys). Scoped to the active project unless you pass all_projects=true, which org owners and admins may do.
/keys/{key_id}JWT onlyUpdate an API key's name, model pool, or optimization mode.
/keys/{key_id}JWT onlyRevoke an API key permanently. Cannot be undone.
Create key with routing config
{
"name": "Production",
"model_pool": ["zai-org/GLM-4.7-Flash", "openai/gpt-oss-120b"],
"optimize_mode": "balanced"
}Credits & Usage
/creditsAPI Key or JWTGet your current inference credit balance.
/credits/transactionsAPI Key or JWTList credit transactions (deposits, deductions).
/usageAPI Key or JWTList inference usage logs with token counts, cost, and latency.
Error Codes
| Code | Meaning |
|---|---|
| 401 | Invalid or missing API key |
| 402 | Insufficient credits - top up your account |
| 403 | API key revoked, account deactivated, or email not verified |
| 404 | Model not found - check available models |
| 429 | Rate limited - slow down requests |
| 413 | Request too large: either the body exceeds 1 MiB (base64 images and audio count) or no model in the pool has a context window big enough |
| 422 | Request body failed validation: error.param names the field (routing.optimise, messages[0].content) and detail carries the structured error list. On /v1/messages this is a 400, as Anthropic answers it |
| 502 | Backend error - model may be cold starting, retry |
| 503 | No eligible model. With model="auto" this is the most common failure and it is usually a pool or preset problem, not an outage: nothing in scope satisfies the request's tools, modality, structured-output or quality-floor requirements |
| 504 | Every attempt in the fallback chain timed out |
Unrecognised parameters are rejected with a 422, not ignored. A knob that is accepted is either forwarded to the vendor or refused with a reason, so a 200 always means the request you sent is the request we ran.
Inference error bodies carry both shapes: {"error": {"message", "type", "param", "code", "request_id"}} for OpenAI SDKs, and {"detail": "..."} alongside it for clients written against the older shape. Every exit uses it, including validation failures, rate limits, timeouts and oversized bodies rejected before routing; request_id repeats the X-Request-ID header so a copied error body is enough to raise a support question. typefollows OpenAI's taxonomy (invalid_request_error, authentication_error, permission_error, rate_limit_error, insufficient_quota, api_error), so SDK retry logic works unchanged. Mid-stream failures arrive as an SSE frame shaped {"object": "error", "error": {...}} followed by [DONE], with the routing disposition in code.
Quick Start
Drop-in replacement for the OpenAI SDK. Create an API key in the dashboard, configure your model pool, then use it:
Python (OpenAI SDK)
from openai import OpenAI
client = OpenAI(
api_key="inf_your_api_key",
base_url="https://api.inferbase.ai/api/v1/inference",
)
# Smart routing: picks the best model from your key's pool
response = client.chat.completions.create(
model="auto",
messages=[
{"role": "user", "content": "Explain quantum computing in 3 sentences."}
],
)
print(response.choices[0].message.content)
# Or use a specific model directly
response = client.chat.completions.create(
model="zai-org/GLM-4.7-Flash",
messages=[
{"role": "user", "content": "Hello!"}
],
)
print(response.choices[0].message.content)Node.js (OpenAI SDK)
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "inf_your_api_key",
baseURL: "https://api.inferbase.ai/api/v1/inference",
});
const response = await client.chat.completions.create({
model: "auto",
messages: [
{ role: "user", content: "Explain quantum computing in 3 sentences." }
],
});
console.log(response.choices[0].message.content);curl (Streaming)
curl -N -X POST https://api.inferbase.ai/api/v1/inference/chat/completions \
-H "Authorization: Bearer inf_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"model": "auto",
"messages": [{"role": "user", "content": "Hello!"}],
"stream": true
}'