Providers and models
Add model providers with a key, point the gateway at any compatible endpoint, and see how a model name picks a provider.
A provider is where the gateway sends model calls. It is either a built-in vendor plus a key, or any endpoint that speaks a supported format.
[providers.openai]
vendor = "openai"
key = "env:OPENAI_API_KEY"
[providers.anthropic]
vendor = "anthropic"
key = "env:ANTHROPIC_API_KEY"The table name (openai, anthropic) is the provider’s name. You use it in routes and in provider/model names. Write keys as env:NAME to keep them out of the file; a literal string also works.
Built-in vendors
A vendor already knows its base URL, how it takes a key, and which formats it speaks.
vendor | Key variable | Formats |
|---|---|---|
openai | OPENAI_API_KEY | openai-chat, openai-responses, openai-realtime, responses-ws, openai-images, openai-transcriptions, openai-speech, openai-embeddings |
anthropic | ANTHROPIC_API_KEY | anthropic-messages |
gemini | GEMINI_API_KEY or GOOGLE_API_KEY | gemini-generate, openai-chat, gemini-live, gemini-images, gemini-veo, openai-embeddings |
respan | RESPAN_API_KEY | openai-chat, openai-responses, anthropic-messages, gemini-generate, decisions |
typesafe | TYPESAFE_API_KEY | decisions |
groq | GROQ_API_KEY | openai-chat, openai-transcriptions, openai-speech |
deepseek | DEEPSEEK_API_KEY | openai-chat |
openrouter | OPENROUTER_API_KEY | openai-chat |
xai | XAI_API_KEY | openai-chat, openai-images |
mistral | MISTRAL_API_KEY | openai-chat, openai-embeddings, openai-transcriptions, openai-speech, mistral-realtime |
together | TOGETHER_API_KEY | openai-chat, openai-images, openai-embeddings |
fireworks | FIREWORKS_API_KEY | openai-chat, openai-embeddings |
cerebras | CEREBRAS_API_KEY | openai-chat |
perplexity | PERPLEXITY_API_KEY | openai-responses |
azure | AZURE_OPENAI_API_KEY | openai-chat |
cloudflare | CLOUDFLARE_API_TOKEN | openai-chat, openai-embeddings |
ollama | none | openai-chat, openai-embeddings |
vllm | none | openai-chat |
OpenAI, Anthropic, Gemini, Respan and TypeSafe are verified end to end against the live API. The others are maintained but not yet verified that way. azure and vllm need a base_url. cloudflare needs CLOUDFLARE_ACCOUNT_ID or a base_url.
No config file
With no gateway.toml, every vendor whose key is set in the environment becomes a provider, named after the vendor:
export OPENAI_API_KEY=sk-...
export ANTHROPIC_API_KEY=sk-ant-...
respan-gatewayOllama is added if OLLAMA_HOST is set. RESPAN_<VENDOR>_BASE_URL moves a vendor’s base URL, for example RESPAN_OPENAI_BASE_URL=https://my-proxy.example/v1. Both only apply without a config file. With one, only the file’s base_url counts. respan-gateway init writes a config file from what it finds in the environment.
Base URLs
base_url replaces a vendor’s URL. It is the URL the vendor’s own SDK takes: OpenAI-compatible ones include the version (https://api.openai.com/v1), Anthropic’s does not (https://api.anthropic.com).
[providers.openai]
vendor = "openai"
key = "env:OPENAI_API_KEY"
base_url = "https://my-proxy.example/v1"A vendor whose formats sit at different URLs, such as Gemini, moves them with a table of formats, one base URL per format:
[providers.gemini]
vendor = "gemini"
key = "env:GEMINI_API_KEY"
formats = { gemini-generate = "https://gemini.internal/v1beta", openai-chat = "https://gemini.internal/v1beta/openai" }Only the formats in the table are served. A single base_url on such a vendor is refused, since it can’t say where each format is.
OpenAI-compatible endpoints
Anything that speaks a supported format is a provider. Give it formats and a base_url instead of a vendor:
[providers.local]
formats = ["openai-chat"]
base_url = "http://localhost:8000/v1"
key = "env:LOCAL_KEY" # optionalformats is one format name or a list. The chat formats are openai-chat, openai-responses, anthropic-messages and gemini-generate; see API formats for the rest. key is sent the way the format expects. To send it in a different header, use auth instead:
[providers.internal]
formats = ["openai-chat"]
base_url = "https://llm.internal/v1"
auth = { type = "header", name = "x-internal-key", key = "env:INTERNAL_KEY" }
# or: auth = { type = "bearer", key = "env:INTERNAL_KEY" }A provider with no key, no auth and no vendor key passes on the client’s own credentials.
Local models
[providers.ollama]
vendor = "ollama" # http://localhost:11434/v1 by default
proxy = false # skip [network]'s proxy, if you set oneTo reach Ollama on another machine, set base_url = "http://gpu-box:11434/v1". Without a config file, set OLLAMA_HOST=gpu-box:11434.
How a model name picks a provider
The model in each request decides where it goes. The gateway tries, in order:
- A route with exactly that name, such as
smart. provider/model: the provider named before the first/gets the rest as the model.anthropic/claude-haiku-5-5goes to the provider namedanthropic;groq/openai/gpt-oss-20bsendsopenai/gpt-oss-20btogroq.- The first glob route that matches, such as
[routes."claude-*"]. - The provider whose model list has it. The gateway reads every provider’s model list at start and every 10 minutes, so
claude-haiku-5-5goes to Anthropic andgpt-6-lunato OpenAI with no routes at all. - Otherwise, the default provider for that kind of request: the first provider in the file that serves it.
The provider can speak a different format from the client. An Anthropic SDK asking for a GPT model is translated to OpenAI’s format and back.
To set the default yourself, or to turn off model lists:
[plugins.routing]
default = "openai"
listings = false # route by routes and provider/model names onlyGET /ui/api/routes/explain?model=M shows where a model would go and why. See Routes and fallback.
List models
GET /v1/models merges every provider’s model list into one OpenAI-shaped list. Each model is named the way a client should ask for it: as is, if routing sends that name to its provider, otherwise as provider/model.
curl http://localhost:8080/v1/models
respan-gateway models # the same list from the command lineEach entry has id, owned_by (the provider) and kind (chat, embedding, image, transcription, speech, video or realtime). GET /v1beta/models returns the same list in Gemini’s shape, and /v1/models with an anthropic-version header returns Anthropic’s.
Respan as a provider
A Respan API key reaches the models in Respan’s gateway catalog with one key:
[providers.respan]
vendor = "respan"
key = "env:RESPAN_API_KEY"Respan speaks OpenAI Chat, OpenAI Responses, Anthropic Messages and Gemini’s generateContent. The gateway sends each model in its maker’s own format (Claude models as Anthropic Messages, Gemini models as generateContent) and anything else as Chat Completions. Its model list is Respan’s public catalog.
To trace requests in Respan rather than route through it, see the respan plugin in Plugins.