# Chat Completions

`POST https://api.llm.buzz/api/v1/chat/completions`

Send a conversation, get the next message. OpenAI's Chat Completions API: the OpenAI and OpenRouter SDKs call it unchanged. Set `stream: true` for server-sent events, which end with a usage chunk and `data: [DONE]`.

Authentication: an inference key, as `Authorization: Bearer KEY`.

## Parameters

- `Idempotency-Key` (header string): A retry with the same key and the same body never runs the request twice: it returns the first answer, or 409 `idempotency_replay_unavailable` when that answer is not stored where the retry arrived. Send the same key again only when the first call got no answer, or after an answer carrying `x-gateway-admission-refused: true`; after any other error answer send a new key. A retry without the key, or with a new one, runs and bills the request again. Reusing a key with a different body answers 409 `idempotency_conflict`.
- `x-session-id` (header string): Names the conversation, as `session_id` does, so its turns stay on the provider that holds its cache.

## Body

- `model` (string, required): A model's name from `GET /api/v1/models`, such as `deepseek/deepseek-v4.1-flash`. A suffix changes one request: `:floor` tries the cheapest provider first and `:nitro` the fastest. On Chat Completions and Responses `:online` asks for a web search, which llm.buzz does not run today: the request is served without one and `x-sgr-ignored-parameters` names `web_search->dropped(search_unavailable)`, or for an organization whose requests llm.buzz keeps in the EU it answers 400 `web_search_unavailable_in_region`. On Messages `:online` does nothing and is named as `model:online`.
- `messages` (object[], required): The conversation, as OpenAI's message objects: `system`, `user`, `assistant` and `tool` roles. A user message may carry `image_url` parts for models that read images, and a `text` part may carry `prompt_cache_breakpoint`, OpenAI's explicit cache mark.
- `stream` (boolean): Stream the answer as server-sent events.
- `max_tokens` (integer): The most tokens the answer may use. Also bounds what the request holds of your balance while it runs.
- `temperature` (number): Sampling temperature. A model that takes none drops it and names it in `x-sgr-ignored-parameters`.
- `tools` (object[]): Functions the model can call, in OpenAI's shape. `{"type": "openrouter:tool_search"}` declares a tool search, and a tool with `defer_loading: true` beside `function` waits for it.
- `tool_choice` (string or object): `auto`, `none`, `required`, or an object naming one function.
- `response_format` (object): `{"type": "json_schema", ...}` asks for an answer in a JSON schema; `{"type": "json_object"}` for any JSON object.
- `reasoning` (object): Reasoning controls, translated for each provider.
  - `effort` (string): How hard the model thinks. An effort the model does not take becomes the nearest one it does, named in `x-sgr-ignored-parameters`.
  - `max_tokens` (integer): A reasoning budget in tokens.
  - `enabled` (boolean): Turn reasoning on or off.
  - `exclude` (boolean): Keep the reasoning text out of the answer while the model still reasons.
- `include_reasoning` (boolean): OpenRouter's older switch: `true` is `reasoning: {}`, `false` is `reasoning: {exclude: true}`.
- `provider` (object): Steers one request across the model's providers. With the OpenAI SDK, send it in `extra_body`. Every field accepts `null`. A name matches a provider's display name, its tag or the tag's first part, ignoring case: `llm.buzz` or `llm-buzz` names llm.buzz's own provider, and `llm-buzz/eu` only its capacity in the EU.
  - `order` (string[]): Try these providers first, in this order, then the others. At most 64 names.
  - `only` (string[]): Use only these providers.
  - `ignore` (string[]): Never use these providers.
  - `allow_fallbacks` (boolean): `false` stops moving to other providers.
  - `sort` (string, one of `price`, `throughput`, `latency`, `smart`): The order to try providers in. Ignored when `order` is set.
  - `zdr` (boolean): `true` keeps the request on providers that declare 0 days of retention.
  - `data_collection` (string, one of `allow`, `deny`): `deny` keeps the request on providers that declare no training and 0 days of retention.
- `session_id` (string): A name for the conversation, 1 to 256 characters, so its turns stay on the provider that holds its cache.
- `cache_control` (object): Anthropic's prompt-cache marker, `{"type": "ephemeral"}` with an optional `ttl` of `"5m"` or `"1h"`. llm.buzz passes it on and never adds one. Claude models cache only where a request marks it.
- `prompt_cache_options` (object): OpenAI's explicit caching, for GPT-5.6 and later models: `mode` `implicit` (OpenAI's default) or `explicit` (OpenAI writes the cache only at a `prompt_cache_breakpoint`), and `ttl` `30m`.
- `prompt_cache_retention` (string, one of `in_memory`, `24h`): OpenAI's cache retention. `24h` with `provider.zdr`, `provider.data_collection: "deny"` or your organization's no-retention policy is a 400 `invalid_request`.
- `web_search_options` (object): Asks for a web search, as the `:online` suffix does. llm.buzz runs none today: the request is served without a search, nothing is billed for one, and `x-sgr-ignored-parameters` names it as `web_search->dropped(search_unavailable)`. An organization whose requests llm.buzz keeps in the EU gets 400 `web_search_unavailable_in_region` instead.

## Responses

- 200: The answer. `provider` names the provider that answered, and `usage.cost` is the request's cost in US dollars when every part of it is known.
- 400: A field is missing or malformed (`invalid_request`, with `metadata.param`), or the model cannot do what the request asks (`unsupported_capability`).
- 401: No key, or the key is unknown, expired, revoked or disabled.
- 402: Your balance is spent and the model is not free, or the request could cost more than your balance.
- 404: No model has this name, or your key may not call it.
- 409: The `Idempotency-Key` was used before. `idempotency_replay_unavailable`: the first request was accepted, and its answer is not stored where this retry arrived, so it was not run again; retry with the same key after a short backoff first, when the first call got no answer, and send a new key to run the request again (it is billed again) or after an error answer. `idempotency_conflict`: the key came with a different body; use a new key for each distinct request. Neither runs the request again.
- 429: Providers are throttling, or the model is at capacity (`unavailable_route`): retry after `Retry-After` seconds. Or a free offer's allowance is used (`free_allowance_exceeded`): your organization's tokens, or your key's requests per minute. Choose a paid model, or for the per-minute limit retry after `Retry-After` seconds.

## Example (curl)

```bash
curl -X POST https://api.llm.buzz/api/v1/chat/completions \
  -H "Authorization: Bearer $LLM_BUZZ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "deepseek/deepseek-v4.1-flash",
  "messages": [
    {
      "role": "user",
      "content": "Say hello in one word."
    }
  ]
}'
```

## Example (Python)

```python
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.llm.buzz/api/v1", api_key=os.environ["LLM_BUZZ_KEY"])
reply = client.chat.completions.create(
    model="deepseek/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Say hello in one word."}],
)
print(reply.choices[0].message.content)
```

## Example (TypeScript)

```ts
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.llm.buzz/api/v1", apiKey: process.env.LLM_BUZZ_KEY });
const reply = await client.chat.completions.create({
  model: "deepseek/deepseek-v4.1-flash",
  messages: [{ role: "user", content: "Say hello in one word." }],
});
console.log(reply.choices[0].message.content);
```

## Example response

```json
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "model": "deepseek/deepseek-v4.1-flash",
  "provider": "Prime Intellect",
  "choices": [
    {
      "index": 0,
      "message": {
        "role": "assistant",
        "content": "Hello!"
      },
      "finish_reason": "stop",
      "native_finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 3,
    "total_tokens": 15,
    "cost": 0.0000072
  },
  "system_fingerprint": null
}
```
