Gateway
Chat Completions
The Gateway's only inference endpoint. OpenAI-compatible request and response, with routing, cost and quota reported in headers.
Authenticate with an API key as a bearer token. Keys look like lsk_live_<8 hex><48 hex> and need the inference scope. Two legacy credentials are still accepted — an agent's gateway token and the platform agent secret — because rows minted before the agent-VM runtime was retired still authenticate. Nothing issues new ones.
Request body
- messagesarrayrequired
- Chat messages with a
roleofsystem,user,assistantortool.contentmay be a string or an OpenAI content-part array; the array form is passed through to the provider untouched. Assistant messages may carrytool_calls, and tool messages atool_call_id. An empty array is a 400. - modelstringdefault: "auto"
- A Lobstack model key, or
"auto". Omit it and the Gateway uses the calling credential's configured model, falling back toauto. A named model is a ceiling, not a command: a simple request under a flagship model still routes down. See Token Intelligence. - streambooleandefault: false
- Return server-sent events instead of a single JSON body. The routing and quota headers are still sent; the cost headers are not, because token counts do not exist yet when the headers flush.
- max_tokensinteger
- Maximum tokens to generate. Defaults to 4096 for Anthropic and for classic OpenAI-compatible providers, and to 8192 for OpenAI's GPT-5 and o-series models, where it is sent as
max_completion_tokensbecause those models rejectmax_tokens. - temperaturenumber
- Forwarded only when you set it, and only to models that accept it. The Gateway never invents a default. When it drops one it says so in
x-lobstack-dropped-params. See Temperature below for the exception. - toolsarray
- OpenAI function-tool definitions:
{ type: "function", function: { name, description?, parameters? } }. Passed straight through on OpenAI-compatible providers and translated to Anthropic'sinput_schemaform for Claude models. - session_idstring
- Free-form grouping key. Recorded on the ledger row so a multi-turn conversation can be costed as one thing. Not sent to the provider.
top_p, tool_choice, n, stop, response_format or stream_options and the request succeeds with those fields dropped silently. They are not forwarded and no header reports it.Response
id is chatcmpl- followed by the request id, so the completion and its trace row share an identifier. model is the Lobstack key that actually served the request — read it rather than assuming it echoes what you sent. There is always exactly one choice.
usage carries the provider's own token counts, which is what the ledger prices. Every other fact about the request is in the headers, listed in full on Metering & cost.
Streaming
Set "stream": true and the response is text/event-stream with X-Accel-Buffering: no, so an intermediate proxy cannot hold the whole answer and defeat the point. Chunks are OpenAI chat.completion.chunk objects.
The first chunk carries the role and empty content, so a client can render the assistant turn before any text arrives. Then come content deltas, then a chunk with a finish_reason, then a usage-only chunk, then data: [DONE].
choices array and is sent unconditionally — you do not need to ask for it with stream_options.include_usage, which the Gateway does not read anyway. It is the last data event before [DONE], and on a streamed request it is the only place the price appears: the cost, savings, baseline and priced headers are all absent, because the headers are already gone by the time the provider says how many tokens it used. The same figures come back in the body instead, under x_lobstack — including baseline_reason, which says whether the saving is measured against a model you named or against the most expensive one your plan allows. The usage object keeps the exact OpenAI shape, so an SDK that does not know us parses it unchanged and ignores the rest. Metering has the field list.A failure part-way through a stream cannot change the status code, which is already 200. The Gateway sends an error object into the stream instead, followed by [DONE], and the trace row records the real status. Tokens the provider already produced are metered even if you hang up early: the generator is cancelled and the ledger write still runs.
Tool calls
Pass tools and the model may answer with tool_calls on the assistant message instead of content. Anthropic models go through a translation layer — tool_use blocks in, OpenAI tool_calls out — so one shape works across every provider. When a model returns tool calls with no text, content is an empty string rather than null.
Streamed tool calls arrive as deltas inside delta.tool_calls, each carrying an index; the id and function.name appear on the first delta for that index and function.arguments accumulates across the rest. Assemble by index, not by arrival order.
Send the result back as a message with "role": "tool" and the tool_call_id you were given. Every turn of a tool loop is a separate request, separately scored and separately routed, so a loop can start on a small model and finish on a larger one.
Temperature
The Gateway forwards temperature only when you set it, and only to models that still accept it. Anthropic deprecated the sampling parameters on Opus 4.7 and everything after it, including Opus 5, Sonnet 5 and the Fable line, and the API returns a hard 400 rather than ignoring the field.
When a temperature is dropped for that reason the response carries x-lobstack-dropped-params: temperature. Erroring would fail a request that is otherwise serviceable; ignoring it silently would leave you wondering why sampling has no effect.
| Model family | temperature sent? | Header? |
|---|---|---|
| Claude Haiku 4.5, Sonnet 4.5, Opus 4.6 | Yes, when you set one | — |
| Claude Opus 5, Sonnet 5, Fable 5.1 | No — provider rejects it | x-lobstack-dropped-params |
| OpenAI GPT-5 and o-series | No — provider only accepts its default | None. This one is silent. |
| Everything else | Yes, when you set one | — |
x-lobstack-dropped-params is driven by the Anthropic rule alone, so it is not set in that case. If you need to know whether sampling was applied on those models, assume it was not.Full examples
Buffered
Streaming
Errors
Every failure is JSON with the same shape, and every one carries the request id, including the ones that fail before authentication finishes.
type is one of six error classes. Errors & retries covers what causes each one and which are worth retrying.