API Reference

Chat completions

Create OpenAI-compatible chat completions, with optional Inferada processors, routing controls, and operational metadata.

Overview

Send an OpenAI Chat Completions request to /v1/chat/completions. Add an optional inferada object when the request needs processors or gateway-specific routing. Standard response fields remain unchanged. Operational metadata appears under the top-level inferada object, while billing metadata appears under usage.inferada. Unknown OpenAI request fields pass through to the model.

Compatibility and Inferada extensions

Inferada additions do not replace standard fields. Clients that ignore unknown JSON fields can continue to use the OpenAI-compatible response. Chat Completions and Responses place Inferada metadata in the same locations for buffered responses and terminal stream events.

inferadaobject
Top-level operational metadata: request_id, timings, routing, processors, tools, buffering and guard outcomes.
usage.inferadaobject
Billing-only metadata. Currently contains cost_eur; operational fields never appear here.
x-request-idheader
Stable request correlation for every transport, including binary audio and file responses.

The @inferada-ai/ai-sdk-provider package maps these additions to providerMetadata.inferada in the Vercel AI SDK. Use its .passthrough provider when application code should receive only standard AI SDK result fields. The raw client also exposes client.passthrough, which removes Inferada metadata from OpenAI-shaped JSON and SSE data. Transport headers remain available in both modes.

typescript
import { createInferada } from '@inferada-ai/ai-sdk-provider'
import { generateText } from 'ai'

const inferada = createInferada({ apiKey: process.env.INFERADA_API_KEY })

// Enriched: result.providerMetadata?.inferada
const enriched = await generateText({ model: inferada('your-model-id'), prompt: 'Hello' })

// Clean AI SDK result: no Inferada metadata extraction
const clean = await generateText({ model: inferada.passthrough('your-model-id'), prompt: 'Hello' })

Create a chat completion

POST/v1/chat/completions
Scopecompletions

Create a buffered response or stream incremental output with Server-Sent Events (SSE).

Request

modelrequiredstring
ID of the model to use. Use /v1/models to discover available ones.
messagesrequiredarray
Array of messages with role (system / user / assistant / tool) and content. The system role is rendered server-side per the model's configured template_render_mode. See Prompt templating.
streamboolean
Set to true to receive incremental SSE chunks. Defaults to false. A processor that needs the complete response can force buffering.
temperaturenumber
Sampling temperature. Standard OpenAI semantics.
top_pnumber
Nucleus sampling.
max_tokensnumber
Max tokens to generate in the completion.
stopstring | string[]
Stop sequences.
frequency_penaltynumber
Standard OpenAI parameter.
presence_penaltynumber
Standard OpenAI parameter.
toolsarray
Tool / function definitions the model can call.
tool_choicestring | object
How the model picks tools.
response_formatobject
E.g. { type: "json_object" } for structured output.
inferadaobject
Inferada's extension namespace. It carries processors: string[], an optional language string, and processor-specific config. See the Processors guide for the catalogue and per-processor shape.
inferada.haystackobject
Caller-side structured context: { data, schema?, format?, redact? }. Activate by including "haystack" in inferada.processors. See the Haystack guide for the field-def shape and the published meta-schema.
inferada.system_modestring
"merge_default" (default) or "replace_default". Controls whether the model's configured default system prompt is merged into the assembled upstream system prompt or skipped. See the system-prompt assembly guide.
json
{
  "model": "qwen3.5-35b",
  "messages": [
    { "role": "system", "content": "You are a helpful assistant." },
    { "role": "user", "content": "Hello!" }
  ],
  "stream": false,
  "temperature": 0.7,
  "max_tokens": 1000
}

Response · 200

Buffered response. The standard OpenAI fields are preserved. Operational additions live under inferada, billing additions under usage.inferada, and timings remains as a transitional legacy alias.

idstring
Completion ID. Derived from the request correlation ID.
choicesarray
Array of completion choices (OpenAI shape).
usageobject
Standard token counts. usage.inferada is a billing-only extension containing cost_eur when pricing is available.
timingsobject
Transitional alias of inferada.timings. New integrations should use the namespaced field.
inferadaobject
Operational metadata. Always includes request_id; may include timings, routing, processor summaries, tool summaries, and guard outcomes. See the Processors guide.
json
{
  "id": "chatcmpl-550e8400-e29b-41d4-a716-446655440000",
  "object": "chat.completion",
  "created": 1704900000,
  "model": "qwen3.5-35b",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello! How can I help?"
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 25,
    "completion_tokens": 8,
    "total_tokens": 33,
    "inferada": {
      "cost_eur": 0.000014
    }
  },
  "timings": {
    "total_ms": 870,
    "upstream_ms": 820,
    "tokens_per_second": 38.5
  },
  "inferada": {
    "request_id": "550e8400-e29b-41d4-a716-446655440000",
    "timings": {
      "total_ms": 870,
      "upstream_ms": 820,
      "tokens_per_second": 38.5
    }
  }
}

Errors

Possible errors include 400 for an invalid body or unknown processor,401 for an invalid token, 403 for a scope or IP restriction,404 for an unavailable model, 422 for a processor policy rejection or missing or unsupported inferada.language; see Processors), 429 for a rate or concurrency limit, 500 for an internal gateway or processor failure, and 502 for an upstream failure. See Errors and Rate limits.

Streaming

With stream: true, the endpoint responds with Server-Sent Events and Content-Type: text/event-stream. Each chunk is an OpenAI-compatible delta frame, and [DONE] terminates the stream. The final success or error chunk includes top-level inferada metadata even when stream_options.include_usage is false. When usage is requested, a separate chunk with an empty choices array contains token counts and usage.inferada.

Streaming uses an idle timeout that resets whenever a chunk arrives. If the upstream produces no chunk within that window, the gateway aborts the stream with a service-failure error. Buffered requests use a fixed request deadline.

text
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"role":"assistant","content":"Hello"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"!"},"finish_reason":null}]}

data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"inferada":{"request_id":"...","timings":{"upstream_ms":820}}}

data: [DONE]

Some processors require the full response, so the gateway disables streaming for that request. See the Processors guide for details.

Processors

Processors add redaction, output correction, policy checks, or routing controls to a completion. See the Processors guide.

Tools

The gateway supports the OpenAI tools and tool_choice request fields. When you send tool definitions, the gateway forwards them to the model verbatim, streams tool_calls deltas back on the wire, and stays out of the execution loop: your client runs the tool and sends the result in a follow-up turn. When the request does not define tools, the model can use the catalogue tools attached by your organisation, which the gateway executes. See the Tools guide.

Timings

Every buffered completion includes the latency breakdown at inferada.timings. The same value is temporarily mirrored at top-level timings for existing integrations:

total_msnumber
End-to-end latency, including queue time and gateway processing.
upstream_msnumber
Time spent in the upstream model request.
tokens_per_secondnumber
Completion-token throughput computed from upstream_ms. Present only when completion tokens are greater than zero.
processors_msnumber
Measured aggregate of pre + post processor time. Only present when processors ran. See Processors.
queued_msnumber
Time spent waiting for a concurrency slot before processing began. Present only when greater than zero. A non-zero value indicates contention under a max_concurrent rule. Streaming responses expose the same value in the x-inferada-queued-ms header.
gateway_msnumber
Residual time spent in the gateway itself (validation, serialization, accounting writes). Only present when non-zero.

When the selected upstream is vLLM, its numeric performance metrics are preserved in the same object. This includes time_to_first_token_ms, generation_time_ms, and mean_itl_ms. To keep provider timings distinct from gateway timings, vLLM's queue_time_ms is exposed as upstream_queue_ms and its tokens_per_second as upstream_tokens_per_second. Standard OpenAI usage token counts and system_fingerprint remain in their standard top-level locations.

Model aliases

An organisation administrator can create a stable alias for one or more model IDs. For example, send model: "chat" instead of a version-specific model ID. The alias can later point to a different model without requiring a client change.

  • Each alias maps to an ordered chain of real model_ids. The resolver selects the first active entry permitted by the token's allowed_models restriction.
  • The gateway also tries the next eligible target when dispatch fails before a response is committed because of connectivity, timeout, throttling, upstream 5xx, or upstream 404. Caller-invalid and authentication responses such as 400, 401, 403, and 422 are terminal.
  • Content processors run once and remain in force across attempts. A fallback target is eligible only when its effective processor policy matches the policy already executed; explicit request processor settings apply to every target. Route policies such as require_local are evaluated against every concrete candidate before any upstream request is sent.
  • The standard response model remains the requested alias. Inspect inferada.routing for resolved_model, fallback_used, dispatch_attempts, and the optional fallback_reason.
  • Once streaming output is visible, or a gateway-executed tool has produced effects, the route is fixed and no transparent retry occurs.
  • Real model_ids always win over aliases: adding an alias never shadows an existing model.
  • Aliases are discoverable via /v1/models: each model entry carries an aliases array listing every alias key that routes to it.
  • When an administrator sunsets a model, its database identity and historical references are retained. Existing aliases promote their next active target; the old concrete model ID can also be retained as an alias to a chosen replacement.
  • Aliases are scoped per service. The completions service's chat and the TTS service's chat would be independent.

List available models

GET/v1/models

List chat and embedding models available to the token. The OpenAI-compatible response includes additional display and service metadata.

Request

Optional query parameters:

scopestring
Narrow to one model scope: "completions" (chat) or "embeddings". Omit to list both. An unrecognised scope returns an empty list.
service_idstring
Narrow to a single service (see GET /v1/services). Omit to span every service.
bash
# All models
curl https://api.inferada.com/v1/models -H "Authorization: Bearer inf_YOUR_TOKEN"

# Only embedding models
curl "https://api.inferada.com/v1/models?scope=embeddings" -H "Authorization: Bearer inf_YOUR_TOKEN"

Response · 200

Each model includes the standard fields plus additional metadata (scope, display_name, description, aliases) and an additive inferada object identifying the owning service. OpenAI clients that ignore unknown response fields remain compatible.

json
{
  "object": "list",
  "data": [
    {
      "id": "qwen3.5-35b",
      "object": "model",
      "created": 1704900000,
      "owned_by": "inferada",
      "scope": "completions",
      "display_name": "Qwen 3.5 35B",
      "description": "General-purpose chat model with 128K context.",
      "aliases": ["chat", "smart"],
      "inferada": {
        "service_id": "01J6A...",
        "service_name": "LLM vLLM",
        "service_is_default": false,
        "processing": "local",
        "pricing": {
          "currency": "EUR",
          "input_per_mtok": 0.4,
          "cached_input_per_mtok": 0.1,
          "output_per_mtok": 1.2
        },
        "default_processors": ["anonymise"],
        "default_language": "nl",
        "tools": { "gateway": ["web_search"], "mcp_servers": [] },
        "processor_languages": { "anonymise": ["en", "nl"], "haystack": ["en", "nl"] }
      }
    }
  ]
}
inferada.processing"local" | "remote" | null
Where the model runs: on infrastructure your organisation controls, or at an external provider. For chat models this is exactly what require_local checks; null means the upstream is not classified, which require_local treats as not local.
inferada.pricingobject | null
List prices in EUR per million tokens (input, cached input, output), before allowances. Image models use the same fields. null when usage on this model is not billed, and for image models where billed requests are refused because the upstream is not local.
inferada.default_processorsstring[]
Chat models only (empty elsewhere): processors that run when a request sends no processors. A request that sends inferada.processors replaces this list, so include these if you still want them.
inferada.default_languagestring | null
Chat models only: the inferada.language applied when a request sends none.
inferada.toolsobject
Chat models only: tools the gateway executes for this model (gateway tool names) and the MCP servers whose tools it adds.
inferada.processor_languagesobject
Chat models only: for each processor that needs inferada.language (anonymise, haystack, spellcheck), the languages your organisation supports. A processor is absent when your organisation has no service for it.

The scope field tells a chat model apart from an embedding model. The aliases array lists every alias key that resolves to this model (whether as primary or fallback). See Model aliases. If your token has an allowed_models restriction, this list is filtered accordingly.

Retrieve a model

GET/v1/models/{model}

Retrieve one model by ID or alias. Returns the same shape as the list endpoint, or 404 when the model is unavailable to the token. Retrieved by alias, the response describes the model the alias tries first and adds inferada.alias: the models it falls back through, in order, with where each runs. The service is chosen the way a request would choose it (the service_id query parameter, else the default service); when the alias is ambiguous across services, inferada.alias is left out.

Response · 200

json
{
  "id": "qwen3.5-35b",
  "object": "model",
  "created": 1704900000,
  "owned_by": "inferada",
  "scope": "completions",
  "display_name": "Qwen 3.5 35B",
  "description": "General-purpose chat model with 128K context.",
  "aliases": ["chat", "smart"],
  "inferada": {
    "service_id": "01J6A...",
    "processing": "local",
    "alias": {
      "name": "chat",
      "models": [
        { "id": "qwen3.5-35b", "processing": "local" },
        { "id": "qwen3.5-35b-cloud", "processing": "remote" }
      ]
    }
  }
}

Abbreviated: an alias response carries every field of the list entry. With require_local, a request through the alias only uses the local models in this chain.

Attach models in the portal

Models are configured per completion service. From Organisation → Models, an organisation administrator can use either workflow:

  • Add model opens the complete form for one model. Select a template and upstream, enter model_id, and configure any overrides, tools, or limits.
  • Add from templates attaches several global or organisation templates to one upstream. Each model uses the template name as its address. For a profile, that address is upstream_model_id:profile_name, e.g. gpt-4o:code), and inherited defaults resolve from the template at request time. The picker disables a template whose name is already attached to the selected service. Use Clone on the existing model to create a variant.

Both flows enforce one model_id per service, and a new model is callable as soon as the save completes.