Overview
The llm.buzz model API speaks the OpenAI, Anthropic and OpenRouter request and response formats under https://api.llm.buzz/api/v1. This page covers what every route shares: the base URL, authentication, the provider object, request fields and errors. Each endpoint has its own page, with its fields and examples.
Base URL and SDKs
Every model route is under https://api.llm.buzz/api/v1. Point an SDK at it and change nothing else:
| SDK | Setting |
|---|---|
| OpenAI | base_url="https://api.llm.buzz/api/v1" |
| OpenRouter | server_url="https://api.llm.buzz/api/v1" (Python), serverURL: "https://api.llm.buzz/api/v1" (TypeScript) |
| Anthropic | base_url="https://api.llm.buzz/api", without /v1: the SDK adds /v1/messages itself |
Authentication
Send an inference key as a bearer token:
curl https://api.llm.buzz/api/v1/models \
-H "Authorization: Bearer $LLM_BUZZ_KEY"The Messages API also takes the key in x-api-key, the header the Anthropic SDK sends. A management key calls only the key routes below: create one on the console's Keys page, as you create an inference key, and send it the same way. The samples for those routes read it from $LLM_BUZZ_MANAGEMENT_KEY. Authentication covers keys, expiry and spending limits.
Endpoints
| Method and path | What it does |
|---|---|
POST /chat/completions | Chat Completions. Streams with stream: true. |
POST /responses | Responses. The same path also takes a WebSocket upgrade on GET. |
POST /messages | The Anthropic Messages API. |
POST /messages/count_tokens | An estimate of a Messages request's input tokens, {"input_tokens": N}. Costs nothing. |
POST /embeddings | Embeddings, for embeddings models. Never streamed. Embeddings covers it. |
POST /images | OpenRouter's Image API: images from a text prompt, each as base64. Never streamed. Images covers it. |
POST /images/generations | The OpenAI Images API (generations), serving the same image models. Never streamed. |
POST /audio/transcriptions | Speech to text: one audio file in, its text out. Never streamed. Audio covers both audio routes. |
POST /audio/speech | Text to speech: one text in, the whole audio out as MP3 or PCM. |
GET /generation?id= | What a finished request cost, below. |
GET /models | The models your key can call, in OpenRouter's shape. Without a key, the public models. |
GET /models/{author}/{slug} | One model. A model whose name has no / is GET /models/{name}. |
GET /model/{author}/{slug} | The same model, wrapped as {"data": ...}. |
GET /models/{author}/{slug}/endpoints | One model's providers, each with its prices, context length, tag and recent uptime, latency and throughput. GET /models/{name}/endpoints for a name with no /. |
GET /embeddings/models | The embeddings models, as GET /models?output_modalities=embeddings lists them. Without a key, the public ones. |
GET /images/models | The image models your key can call, each with the sizes and values its fields take. Key required. |
GET /images/models/{author}/{slug}/endpoints | One image model's providers, each with the values its fields take and its price per token or per image. GET /images/models/{name}/endpoints for a name with no /. Key required. |
GET /key | The key you send: its kind, its limit, what is left and its spend. |
GET /credits | Your organization's prepaid credit and usage. Management key. |
GET, POST /keys; GET, PATCH, DELETE /keys/{hash} | List, create, change and revoke inference keys. Management key. |
Paths are relative to https://api.llm.buzz/api/v1. Model routes outside it, such as /v1/chat/completions on the bare host, answer 404.
Decisions are served on POST /systemone and on POST https://api.llm.buzz/api/alpha/decisions, and no listed model answers them today. Choosing an API says which API each kind of model takes, and Decisions covers the two routes.
llm.buzz does not enable batch jobs: with a key, /batches and /files answer 404, "batches are not enabled on this gateway". Send a large job as single requests; the batch jobs guide shows how.
The keyless public catalog under /public/v1 (the site facts, every public model and provider) is what the llm.buzz website is built from, and the API reference lists it too. It needs no key, but it is the website's data, not a stable API: its fields can change without notice. Build on GET /models and the endpoints route instead.
The model list
GET /models returns data, total_count and links. Prices are decimal strings in US dollars per token. An audio model's prompt price is per second of audio or per character of input, and an image model lists its output price in image_output (Images explains image prices). Its query parameters:
| Parameter | Effect |
|---|---|
output_modalities | text by default; all lists every model, and a comma list such as text,embeddings lists models that produce any of them. The values are text, image, embeddings, transcription (speech to text) and speech (text to speech). |
limit, offset | Page the list. |
region=eu | Only models with an EU provider, priced over those providers. It changes the listing, never how a call routes. |
A model whose lead provider's listing names its reasoning efforts carries them as reasoning_efforts, in order from none to max. The key is left out otherwise, including for a model whose efforts llm.buzz knows only from its own rules for the model's family, so a model without it can still reason: Reasoning. A speech-to-text model carries verbose_json, and a text-to-speech model supported_voices, default_voice and speech_speed; Audio explains them.
Without an Authorization header the list, a model and its endpoints answer the public catalog, at most 1,000 models, priced at each model's first-ranked public provider.
On the endpoints route, llm.buzz's own provider is one endpoint, provider_name llm.buzz and tag llm-buzz, priced at the lowest live direct price of each component. The llm.buzz provider explains it.
The provider object
Send provider in the request body (with the OpenAI SDK, in extra_body) to steer one request. Chat Completions, Responses, Messages, Embeddings and the image routes read every field; the audio routes read only zdr and data_collection. Every field accepts null.
| Field | Type | Meaning |
|---|---|---|
order | list of strings | Try these providers first, in this order, then the others. |
only | list of strings | Use only these providers. |
ignore | list of strings | Never use these providers. |
allow_fallbacks | boolean | false stops moving to other providers: without order only the first provider is tried, with order only the listed ones. |
sort | string | price tries the cheapest provider first, throughput and latency the fastest, smart weighs price and speed. Ignored when order is set. |
zdr | boolean | true keeps the request on providers that declare 0 days of retention. |
data_collection | string | deny keeps the request on providers that declare no training and 0 days of retention. allow demands nothing. |
order, only and ignore take at most 64 names. A name matches a provider's display name, its tag, or the tag's first part, ignoring case; an EU provider's tag ends in /eu. llm.buzz or llm-buzz names llm.buzz's own provider, and llm-buzz/eu only its capacity in the EU. Models and routing explains the order a model's providers are tried in.
extra_body={"provider": {"only": ["scaleway/eu"], "zdr": True}}Model suffixes
A suffix on the model's name changes one request: :floor tries the cheapest provider first, :nitro the fastest, and :exacto is accepted and ignored. :online asks for a web search on Chat Completions and Responses; on Messages it does nothing and is named in x-sgr-ignored-parameters as model:online.
llm.buzz runs no web search today. A request that asks for one, with :online, web_search_options or plugins: [{"id": "web"}], is still served, without the search: nothing is sent to a search service, no search is billed, and x-sgr-ignored-parameters names it as web_search->dropped(search_unavailable). For an organization whose requests llm.buzz keeps in the EU, such a request answers 400 web_search_unavailable_in_region instead.
Request fields
Each API's page lists every field and what llm.buzz does with it: Chat Completions, Responses and Messages. Fields the surface does not know are dropped instead of refused, and Chat Completions, Responses and Messages name them in x-sgr-ignored-parameters in the response body. A field llm.buzz refuses answers 400 before any provider is called: Errors. These fields do something on llm.buzz:
| Field | Surfaces | Meaning |
|---|---|---|
tools | Chat Completions, Responses, Messages | Functions the model can call, in each API's own shape. |
response_format | Chat Completions | json_schema asks for an answer in a JSON schema; json_object for any JSON object. |
reasoning | Chat Completions, Messages | effort or max_tokens, plus enabled and exclude. Each provider receives it in its own terms. Where a model's efforts are known, an effort it does not take becomes the nearest one it does, named in x-sgr-ignored-parameters; a provider that refuses the setting answers 400 naming the field. exclude: true keeps the reasoning text out of the answer while the model still reasons. Responses takes reasoning.effort, and Chat Completions also takes OpenRouter's include_reasoning: true is reasoning: {}, false is reasoning: {exclude: true}. |
cache_control | Chat Completions, Responses | Anthropic's prompt-cache marker, {"type": "ephemeral"} with an optional ttl of "5m" or "1h". llm.buzz passes it on and never adds one. Messages takes Anthropic's own markers. Prompt caching says when to send it. |
prompt_cache_breakpoint, prompt_cache_options, prompt_cache_retention | Chat Completions, Responses | OpenAI's explicit caching controls, for OpenAI's GPT-5.6 and later models. Prompt caching explains them. |
session_id | Chat Completions, Responses, Messages | A name for the conversation, 1 to 256 characters, so its turns stay on the provider that holds its cache. The x-session-id header works too. |
web_search_options, plugins: [{"id": "web"}] | Chat Completions, Responses | Ask for a web search, as :online does. llm.buzz runs none today: see Model suffixes. |
provider | Every model route | The provider object above. |
gateway | Chat Completions, Responses, Messages | Per-request retries and fallbacks, below. |
defer_loading | Chat Completions, Responses, Messages | On a tool, keeps it out of the prompt until a tool search finds it, below. |
On Chat Completions and Responses, send an Idempotency-Key header. 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 the request again and is billed again. Retries and idempotency says which key to send after each answer, and Errors lists the codes.
Sampling settings a model does not take
Some models refuse sampling settings. The Claude models that only think adaptively (Opus 4.7 onward, Sonnet 5, Haiku 5, Fable 5, Mythos 5) take no temperature, top_p or top_k, and OpenAI's reasoning models take temperature and top_p only where OpenAI does: some never, others only at reasoning effort none. llm.buzz drops such a value instead of failing the request, and names it in x-sgr-ignored-parameters, as temperature->dropped(unsupported_by_provider), or temperature->dropped(set_reasoning_effort_none) where setting the effort to none keeps it.
Two more rules follow the model or the provider:
- Claude models that always think. Claude Opus 5.5, Sonnet 5.5 and the Fable models take no
noneeffort:reasoning_effort: noneandthinking.type: disabledanswer 400 before any provider is called, whichever provider would serve the model. Leave thinking out, or choose an effort: How an effort is mapped. Claude Opus 5.5, Sonnet 5.5 and Fable 5.1 also cannot be forced to call a tool: atool_choicethat forces one is served asautoand named astool_choice->auto, so the answer may come without a tool call. - Moonshot AI's own API, one provider of the Kimi models such as
moonshotai/kimi-k3, takes notemperature,top_p,top_k,frequency_penaltyorpresence_penalty: llm.buzz drops them there, names them inx-sgr-ignored-parameters, and the model answers at its fixed settings. Atool_choicethat names one function goes to another provider of the model that takes it, or is served asautoand named astool_choice->auto. To force a tool call there, sendtool_choice: "required". The Kimi models' other providers keep these settings.
Retries and fallbacks per request
The gateway object sets bounds for one request. Every field is optional.
extra_body={"gateway": {
"retry": {"max_attempts_per_route": 2, "max_total_attempts": 3,
"backoff": {"type": "exponential", "base_delay_ms": 500, "max_delay_ms": 8000}},
"routing": {"allow_fallbacks": False},
}}| Field | Meaning |
|---|---|
retry.max_attempts_per_route | 1 to 4 calls to one provider, the first included. A cap, not extra retries: a provider that failed is not called again for an ordinary failure. |
retry.max_total_attempts | 1 to 8 calls in all, every fallback included. 8 when omitted. |
retry.backoff | {"type": "none"}, or {"type": "exponential"} with base_delay_ms (default 500), max_delay_ms (default 8000) and multiplier (default 2): the wait before calling a throttled provider again. |
routing.allow_fallbacks | false keeps the request on the first provider, as provider.allow_fallbacks: false does. |
These are ceilings: the request's time limit, your spending limits and a provider's health can stop it sooner. Once output has reached you, the request stays on the provider that sent it.
Tool search
With many tools, mark most of them defer_loading: true and declare a tool search tool. The model then sees only the other tools and a search; the tools a search finds join the request. Where every provider of the model searches natively, the provider does it; otherwise llm.buzz runs the search, up to 3 rounds per request.
| Surface | Declare | Mark |
|---|---|---|
| Messages | {"type": "tool_search_tool_bm25"} or {"type": "tool_search_tool_regex"} | defer_loading: true on the tool |
| Responses | {"type": "tool_search"} | defer_loading: true on the function tool |
| Chat Completions | {"type": "openrouter:tool_search"} | defer_loading: true beside function |
Usage counts the searches in server_tool_use_details.tool_search_requests (server_tool_use.tool_search_requests on Messages).
Responses
usage.costis the request's cost in US dollars, on every surface, when every part of it is known.- Chat Completions and Embeddings bodies, and every Chat stream chunk, carry
provider: the name of the provider that answered,llm.buzzfor llm.buzz's own provider. - Cached input shows in
usage.prompt_tokens_details.cached_tokenson Chat Completions andusage.input_tokens_details.cached_tokenson Responses, and cache writes incache_write_tokensbeside it, withcache_write_1h_tokensfor the one-hour part when the provider reports it. Messages keeps Anthropic's fields,cache_read_input_tokensandcache_creation_input_tokens. Prompt caching lists them. - Every answer carries the headers
x-request-id,x-gateway-alias(the model that served),x-gateway-canonical-model,x-gateway-provider(the provider that answered),x-gateway-route-depthandx-gateway-route-reason. Image and audio answers addX-Generation-Id. - Readable reasoning comes back beside the answer:
message.reasoning(delta.reasoningin a stream) on Chat Completions, athinkingblock on Messages, and a reasoning item'ssummary_texton Responses.reasoning.exclude: trueturns it off. - A Chat Completions model that makes images returns them in
message.images[].image_url.url(delta.imagesin a stream), each a complete base64 image. Send one back as an assistantimage_urlcontent part to continue the conversation.
Cost of a finished request
GET /generation?id= answers the record and cost of any finished request of your organization. A request's generation ID is gen- and the 32 hex digits of its x-request-id, which is request- and the same digits. Image and audio answers also name it in X-Generation-Id, and a text-to-speech answer, which has no JSON body, has its cost only here.
curl "https://api.llm.buzz/api/v1/generation?id=gen-..." \
-H "Authorization: Bearer $LLM_BUZZ_KEY"The answer is OpenRouter's {"data": {...}}. total_cost and usage are what you were charged, in US dollars at your rate; api_type is completions (Chat Completions, Responses and Messages), embeddings, image, stt, tts or decisions; provider_name is the provider that served it. An ID of another organization, a malformed one, and one whose request has not finished all answer 404; a request without id answers 400. Audio lists every key.
Time limit
A request may run for 600 seconds. A stream still generating then ends with a timeout error chunk and the stream terminator, and is billed for the prompt and the output you received, not for its whole reservation. Any other request past the limit answers 504 deadline_exceeded. Usage and limits collects the limits of every API.
Browser access
A web page can call the model API from the browser with its visitor's own key, as on OpenRouter. The key travels in Authorization or x-api-key, never in a cookie, so every answer under /api/ allows any origin and none allows credentials.
- A preflight answers 204 without a key, and a browser keeps its answer for a day. It allows the headers the API reads:
authorization,content-type,accept,x-api-key,anthropic-version,anthropic-beta,x-title,http-referer,idempotency-key,x-session-id,x-client-request-id,originator,openai-organization,openai-project, and anyx-sgr-orx-stainless-header (the OpenAI and Anthropic SDKs send the latter). The browser refuses to send any other header. - Every answer, errors included, lets the page read the headers
x-request-id,x-generation-id,retry-after,x-ratelimit-*andx-gateway-*, and, in the body, thex-sgr-ignored-parameterskey. No answer sends that name as a header. - The keyless catalog under
/public/v1sends no CORS headers. - A key used from a page is visible to that page's visitors. Give a browser app a key with a spending limit, or let each visitor bring their own.
App attribution
Coding agents and apps that llm.buzz recognizes get their usage counted under their own name on Rankings and their app page. Most are recognized by their User-Agent. An app can also name itself with OpenRouter's headers:
-H "X-Title: Cline" -H "HTTP-Referer: https://cline.bot"A title or a site llm.buzz does not know counts as other usage. Neither header is ever published.
Errors
Errors on the model routes come in one envelope; metadata.gateway_code is the code to branch on. The Messages API keeps Anthropic's error body.
{"error": {"code": 404, "message": "...", "metadata": {"error_type": "not_found", "gateway_code": "model_not_found", "param": "model"}}}| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_parameter | A request field fails validation, such as a missing messages or input, an out-of-range temperature or n other than 1; metadata.param names it, or body when the fault spans fields. |
| 400 | invalid_json | The body is not JSON. |
| 400 | unsupported_parameter | A field llm.buzz refuses; metadata.param names it. The pages of Chat Completions, Responses and Messages list the fields each refuses. |
| 400 | invalid_request | llm.buzz read the body and refused the request: a provider's own 400, whose sentence follows provider rejected the request:, or another refusal the message explains. |
| 400 | unsupported_capability | The model or its providers cannot do what the request asks, such as a service_tier of flex, priority or fast on Chat Completions and Responses. |
| 400 | context_length_exceeded | The prompt fits no provider's context window. |
| 400 | web_search_unavailable_in_region | The request asked for a web search, and your organization's requests are kept in the EU. |
| 401 | invalid_key | No key, or the key is unknown, expired, revoked or disabled. |
| 402 | insufficient_credits | Your balance is spent and the model is not free. |
| 403 | key_limit_exceeded | The key's spend in its period has reached its limit. |
| 403 | management_key_not_allowed | A management key called a model route. |
| 404 | model_not_found | No model has this name, or your key may not call it. |
| 404 | model_unavailable | No provider of the model can serve it right now. |
| 404 | no_allowed_providers | Your provider preferences leave no provider. Nothing was sent. |
| 404 | model_not_available_under_data_policy | No provider meets zdr, data_collection or your organization's data policy. Nothing was sent. |
| 409 | idempotency_conflict | An Idempotency-Key was reused with a different body. |
| 409 | idempotency_replay_unavailable | A request with this Idempotency-Key was already 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; a new key runs the request again and bills it again, and after an error answer a new key is the only way. |
| 413 | request_too_large | The request body is over the size limit, such as an audio file over 25 MiB. |
| 429 | unavailable_route | Providers are throttling. Retry after Retry-After seconds. |
| 429 | free_allowance_exceeded | A free offer's allowance is used: your organization's tokens, or your key's requests per minute. Choose a paid model, or retry after Retry-After seconds for the per-minute limit. |
| 502 | all_routes_failed | Every provider tried failed. Retry with backoff. |
| 503 | unavailable_route | No provider could answer just now. Retry with backoff. |
| 504 | deadline_exceeded | The request passed its 600-second limit. |
Errors lists every code with what to do.