# Coming from OpenRouter

llm.buzz speaks OpenRouter's API, so most OpenRouter code works after you change the base URL and the key. This page lists what else differs, with links to the pages that explain more.

## Switch your client

Create a key on the console's [Keys](https://app.llm.buzz/console/keys) page. It starts `exp_vk_`. There is no OAuth key exchange: you create a key in the console, and every client sends it as its API key: as a bearer token, or on Messages in `x-api-key`, the header the Anthropic SDK sends ([Authentication](authentication.md#send-the-key)).

| Client | Setting | Value |
|---|---|---|
| OpenRouter Python | `server_url` | `https://api.llm.buzz/api/v1` |
| OpenRouter TypeScript | `serverURL` | `https://api.llm.buzz/api/v1` |
| OpenAI | `base_url` (`baseURL` in TypeScript) | `https://api.llm.buzz/api/v1` |
| Anthropic | `base_url` (`baseURL` in TypeScript) | `https://api.llm.buzz/api` |
| curl | the URL | `https://api.llm.buzz/api/v1/chat/completions` |

The Anthropic address has no `/v1`: the SDK adds `/v1/messages` itself ([Base URL and SDKs](api-reference.md#base-url-and-sdks)). The OpenRouter SDKs call decisions through a server URL of their own: [Decisions](decisions.md#routes). Any other client of these APIs needs only the base URL and the key.

## What works the same

The routes you call are OpenRouter's: Chat Completions, Responses, Messages, Embeddings, Images, speech to text and text to speech, `GET /models` and `GET /models/{author}/{slug}/endpoints` with the same shapes, `GET /generation`, and the key and credits routes `GET /key`, `GET /credits` and `/keys` ([Endpoints](api-reference.md#endpoints)). The `provider` object takes `order`, `only`, `ignore`, `allow_fallbacks`, `sort`, `zdr` and `data_collection` ([Provider preferences](models-and-routing.md#provider-preferences)), and `:nitro` and `:floor` change the order on a model's name ([Suffixes](models-and-routing.md#suffixes)). Errors come in OpenRouter's envelope with `metadata.error_type`, and add `metadata.gateway_code`, llm.buzz's own code to branch on; Messages answers Anthropic's error body ([The envelope](errors.md#the-envelope)). A page can call the API from a browser with its visitor's own key ([Browser access](api-reference.md#browser-access)), and `X-Title` and `HTTP-Referer` name your app ([App attribution](api-reference.md#app-attribution)).

## Request fields that differ

On Chat Completions, Responses and Messages, llm.buzz drops a field it does not know instead of refusing it, and names each dropped field in `x-sgr-ignored-parameters`. That is a key in the response body, never a header: in a Chat Completions body and in the content and finish chunks of its stream, in the Responses object, and in Messages in `message_start` and the final message. Embeddings and Images drop unknown fields without naming them, and Decisions refuse them. A field llm.buzz deliberately refuses is a 400 before any provider is called. On Chat Completions and Responses its `metadata.gateway_code` is `unsupported_parameter` (the field is refused), `invalid_parameter` (only some values are) or `unsupported_capability`, and `metadata.param` names it. Messages renders every field refusal as Anthropic's `invalid_request_error`, with `(param: NAME)` at the end of the message. The same field can be refused on one API and dropped on another:

| Field | What llm.buzz does |
|---|---|
| `models`, `route`, `transforms`, `usage`, `trace`, `debug` | Dropped and named on all three APIs. |
| `plugins` entries other than `web` | Chat Completions and Responses: dropped, named `plugins.<id>`. Messages: `plugins` dropped whole and named. |
| `:online`, `web_search_options`, the `web` plugin | Chat Completions: served without a search. Responses: `:online` and the `web` plugin are served without a search, and `web_search_options`, not a Responses field, is dropped and named. Messages: `:online` is named `model:online`, `plugins` and `web_search_options` are dropped and named, and nothing is searched. |
| `seed`, `logit_bias` | Chat Completions: 400 `unsupported_parameter`. Responses and Messages: dropped and named. |
| `audio`, `modalities`, `functions`, `function_call`, `prediction` | Chat Completions: 400 `unsupported_parameter`. Responses and Messages: dropped and named. |
| `moderation` | Chat Completions and Responses: 400 `unsupported_parameter`. Messages: dropped and named. |
| `stream_options` | Chat Completions: dropped and named when the request does not stream; on a stream `include_usage` changes nothing, because the last chunk carries usage whenever the counts are known. Responses and Messages: dropped and named. |
| `n` other than 1 | Chat Completions: 400 `invalid_parameter`. Responses and Messages: dropped and named. |
| `store` | Chat Completions: `true` is 400 `invalid_parameter`. Responses: used, and `store: false` keeps the turn out of continuation. Messages: dropped and named. |
| `previous_response_id` | Chat Completions: dropped and named. Responses: used, and it continues a kept turn. Messages: dropped and named. |
| `service_tier` | Chat Completions and Responses: `flex`, `priority` and `fast` are 400 `unsupported_capability`; `auto` and `default` are served at the standard tier and not sent on. Messages: 400, naming `service_tier`. |
| `background`, `conversation`, `max_tool_calls`, `prompt` | Chat Completions: dropped and named. Responses: 400 `unsupported_parameter`. Messages: dropped and named. |
| `context_management` | Chat Completions: dropped and named. Responses: 400 `unsupported_parameter`. Messages: sent where the provider takes it, dropped and named elsewhere. |
| `betas`, `container`, `fallbacks`, `fallback_credit_token`, `mcp_servers`, `thread`, `user_profile_id` | Chat Completions and Responses: dropped and named. Messages: 400, naming the field; send `betas` as the `anthropic-beta` header. |

Responses refuses a few more values with 400 `invalid_parameter`: a `truncation` other than `"disabled"`, any `reasoning.mode`, a `text.format.type` other than `text` or `json_schema` (`json_object` included: ask for JSON with a `json_schema` format), and any `include` selector other than `reasoning.encrypted_content` and `message.output_text.logprobs`. Chat Completions takes `response_format: {"type": "json_object"}`. [Chat Completions](chat-completions.md#request-fields), [Responses](responses.md#request-fields) and [Messages](messages.md#request-fields) list every field of their API. [Tools and structured output](tools-and-structured-output.md) covers the tool and format fields.

What happens in place of these fields:

- **Fallback models.** A model's own providers fail over through its routing preset in place of `models`: [How a provider is chosen](models-and-routing.md#how-a-provider-is-chosen). Usage counts and `usage.cost` come back whether or not you send `usage`.
- **Web search** is not available on llm.buzz today. A request that asks for one is still served, without the search; nothing is sent to a search service and nothing is billed for one. `x-sgr-ignored-parameters` names it `web_search->dropped(search_unavailable)`. For an organization whose requests llm.buzz keeps in the EU, such a request is 400 `web_search_unavailable_in_region`. [Suffixes](models-and-routing.md#suffixes).
- **Other `provider` keys.** `require_parameters`, `quantizations`, `max_price` and `sort.partition` are accepted on all three APIs and do not change which provider serves. `provider.sort` takes `price`, `latency`, `throughput` and `smart`; `throughput` ranks like `latency`, by recent time to first token. `exacto`, `:exacto` and any other sort string leave the model's routing preset in place. [The provider object](api-reference.md#the-provider-object).
- **Suffixes.** A suffix such as `:free`, `:extended` or `:thinking` is part of the model's name, which is matched exactly, and no model is listed under such a name today. A name that is not listed answers 404 `model_not_found`. [Model names](models-and-routing.md#model-names).
- **Service tiers.** llm.buzz does not sell a priority tier, and no model has a price for `flex`, `priority` or `fast` today, so on Chat Completions and Responses a request for one is refused with 400 `unsupported_capability`, naming `service_tier`, before any provider is called. `auto` and `default` are served at the standard tier.
- **Conversations.** Responses keeps each finished turn for up to 24 hours: [Continue a conversation](responses.md#continue-a-conversation).

## Routes llm.buzz does not serve

Apart from batches, files, decisions and the two model routes below, an OpenRouter route that is missing from the [Endpoints](api-reference.md#endpoints) table answers 404 `unknown_route` ("Unknown route"). Among them:

- `/completions`, `/rerank` and `/videos`;
- `/providers`, `/endpoints/zdr`, `/activity`, `/analytics/*`, `/generation/content` and `/generation/feedback`;
- `/presets`, `/guardrails`, `/workspaces`, `/organization/*`, `/byok`, `/auth/keys`, `/tools`, `/observability/*` and `/private-endpoints`.

llm.buzz does not enable batch jobs: `/batches` and `/files` answer 404 with a key, "batches are not enabled on this gateway": send a large job as single requests, as the [batch jobs guide](/docs/guides/batch-jobs) shows. `/models/count` and `/models/user` read their last segment as a model name and answer 404 `model_not_found`: read `total_count` on `GET /models` for a count, and list the models your key can call with `GET /models` and your key. Decisions are served, but no public model answers them today: [Decisions](decisions.md).

In their place: a model's endpoints route lists its providers (`/providers`), `provider.zdr` keeps a request on zero-retention providers, and your organization's data policy narrows the endpoints route the same way (`/endpoints/zdr`), the console's Activity page and `GET /generation` cover activity and analytics, and the console's Prompt logs page shows logged prompts (`/generation/content`).

## Features llm.buzz does not offer

- **Router models.** `openrouter/auto` and OpenRouter's other router models name no model on llm.buzz: a request for one answers 404 `model_not_found`. Name a model, and choose its provider order with `provider.sort`.
- **Saved presets.** There is no `/presets` route. llm.buzz's own routing presets (`smart`, `cheapest`, `fastest` and `order`) order one model's providers, and `provider.sort` or a `:floor` or `:nitro` suffix picks one of them for a single request: [How a provider is chosen](models-and-routing.md#how-a-provider-is-chosen).
- **Server tools.** Tool search is the one tool llm.buzz runs for you: [Tool search](api-reference.md#tool-search). Web search is not available, as above, and OpenRouter's other server tools are not offered.
- **Plugins.** No plugin runs. On Chat Completions and Responses an entry in `plugins` is dropped and named `plugins.<id>`, and the `web` plugin is the web search above; Messages drops `plugins` whole.
- **A response cache.** Replay is opt-in, on Chat Completions and Responses only: a retry that carries the same `Idempotency-Key` returns the first answer, and no other request is answered from a stored one. Messages reads no `Idempotency-Key`, so a Messages retry runs and is billed again ([Idempotency-Key](retries-and-idempotency.md#idempotency-key)).
- **Workspaces.** Your keys, the people you invite with their roles and one prepaid balance belong to an organization: [Organizations](authentication.md#organizations).
- **Guardrails.** There is no `/guardrails` route.
- **Bring your own key.** The hosted service has no bring-your-own-key: `is_byok` is `false` on every generation record.
- **Broadcast to observability tools.** There is no `/observability` route. Read your traffic on the console's [Activity](https://app.llm.buzz/console/activity) and [Logs](https://app.llm.buzz/console/logs) pages.
- **SAML single sign-on and SCIM.** Neither is offered. People sign in to the console with an email and a password, Google or GitHub.
- **Regional base URLs.** There is no regional base URL. To keep a request in the EU, list the EU tags in `provider.only`: [EU](models-and-routing.md#eu). `GET /models?region=eu` lists only the models with an EU provider: [The model list](api-reference.md#the-model-list).
- **Video generation.** `/videos` answers 404.
- **`openrouter_metadata`.** Read the `provider` key of a Chat Completions or Embeddings answer and the `x-gateway-*` headers of every answer: [Answer fields and headers](api-reference.md#responses).
- **Other attribution headers.** llm.buzz reads `X-Title` and `HTTP-Referer`. A header such as `X-OpenRouter-Title` is not read, and a browser preflight that asks for it does not allow it, so the browser refuses to send it.

## Answers that differ

- **Endpoint metrics.** `uptime_last_5m`, `uptime_last_30m`, `uptime_last_1d`, `latency_last_30m` and `throughput_last_30m` come from your organization's own traffic. A minute counts as observed with 1 attempt or more, where OpenRouter needs 10. `status` is always 0. Each window ends at the last computed 5-minute bucket, so the values run 2 to 8 minutes behind, and a field is `null` when its window has no sample. Without a key only `uptime_last_1d` can be set. [Endpoints](api-reference.md#endpoints).
- **Key objects.** `GET /key` and the key objects of `/keys` carry fixed values where llm.buzz has no counterpart: the `byok_usage` figures are `0`, `include_byok_in_limit` is `false` and `workspace_id` is `"default"`, and a `/keys` object has `external_user` `null`. `GET /key` also has `is_provisioning_key` `false`, `organization_id` `null`, a `free_model_daily_requests` object whose `limit`, `remaining` and `used` are `0`, and a deprecated `rate_limit`. [Check your key and credit](usage-and-limits.md#check-your-key-and-credit).
- **Creating keys.** `POST /keys` takes `name`, `limit`, `limit_reset` and `expires_at`, and accepts and ignores `include_byok_in_limit`, `workspace_id` and `external`. `external.api_key` is 400, because llm.buzz issues its own keys. Management keys are created only in the console.
- **Reasoning efforts.** A model object has no `reasoning`, `knowledge_cutoff` or `benchmarks` key. The model list names a model's efforts in `reasoning_efforts`, from `none` to `max`, when the model's lead provider's listing names them; the key is left out otherwise, including where llm.buzz knows a model's efforts only from its own rules for the model's family, and no public model names `reasoning` in `supported_parameters` today. A model without the key can still reason: [Reasoning](reasoning.md#which-models-reason).
- **Image models.** An image model's `supported_parameters.size` lists the sizes it takes, and `allowed_passthrough_parameters` is always empty, because llm.buzz checks every field and passes none through. The image model routes need a key: [Find an image model](images.md#find-an-image-model).
- **Audio endpoints.** A text-to-speech endpoint's `max_completion_tokens` is null, and OpenRouter's endpoint flags `supports_voice_cloning`, `supports_diarization`, `supports_image_reference` and `supports_multiple_audio_references` are left out, because no provider here offers those features: [Find an audio model](audio.md#find-an-audio-model).
- **The provider in the answer.** The request's `provider` object works on Chat Completions, Responses and Messages. The answer carries a `provider` key, the name of the provider that answered, only on Chat Completions (every body and stream chunk) and Embeddings. Every answer names its provider in `x-gateway-provider`.
- **Retries.** On Chat Completions and Responses, a retry with the same `Idempotency-Key` returns the first answer, or answers 409 `idempotency_replay_unavailable` when its 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. [What to send next](retries-and-idempotency.md#what-to-send-next) has the cases.

## Prompt logs

llm.buzz keeps the prompts and answers of your organization's Chat Completions, Responses and Messages requests in prompt logs, and logging is on by default. An admin turns it off, or deletes the logged prompts, on the console's Prompt logs page. `provider.zdr` and `provider.data_collection` work as on OpenRouter, and a request with either demand is never logged. [Prompt logs](models-and-routing.md#prompt-logs) explains the rest.

## Billing

- You pay from prepaid credit that your organization buys on the console's [Credits](https://app.llm.buzz/console/credits) page, with a service fee added when you buy: [Prepaid credit](pricing.md#prepaid-credit).
- A provider that fails or sends an empty answer and is replaced by another adds nothing to the cost; you pay the provider that answered. [Retries and idempotency](retries-and-idempotency.md#inside-one-request).
- A free offer is a provider discount with an allowance, not a `:free` model: [Free offers](pricing.md#free-offers).
