API formats
Every API the gateway serves to clients, its endpoints, and which vendors can answer it.
A format is one vendor’s API, such as OpenAI Chat Completions or Anthropic Messages. Your client calls the gateway in its own format. The gateway decodes the request into a neutral type, sends it to the provider in a format that provider speaks, and writes the answer back in the client’s format.
Formats of the same kind translate into each other. A chat client can reach any provider that speaks any chat format. An image client can reach any provider that speaks an image format. Formats of different kinds never mix.
Chat
| Format | Endpoint | Vendors that speak it |
|---|---|---|
openai-chat | POST /v1/chat/completions | OpenAI, Gemini, Respan, Groq, DeepSeek, OpenRouter, xAI, Mistral, Together, Fireworks, Ollama, Azure, vLLM, Cloudflare, Cerebras |
openai-responses | POST /v1/responses | OpenAI, Respan, Perplexity |
anthropic-messages | POST /v1/messages | Anthropic, Respan |
gemini-generate | POST /v1beta/models/{model}:generateContent, POST /v1beta/models/{model}:streamGenerateContent | Gemini, Respan |
A client of any chat format can call a model on any of these vendors. For example, the Anthropic SDK can call gpt-6-luna, and the OpenAI SDK can call claude-haiku-5-5.
Translated between chat formats:
- Streaming. A stream and a whole response are the same events inside the gateway, so a client can stream from a provider that answers whole, and the other way round. A Gemini provider is always asked for SSE.
- Tools. Function tools, tool calls and tool results, including the tool choice where the target format has a form for it.
- Images and documents in messages, by the target format’s rules.
- Reasoning. Effort levels and token budgets map where the target has them (see the table below).
previous_response_id. A Responses client keeps it with any provider. Theresponsesplugin stores the conversation in memory.
Reasoning and sampling settings:
| Setting | OpenAI Chat | Responses | Anthropic | Gemini |
|---|---|---|---|---|
| Effort off | reasoning_effort: "none" | reasoning.effort: "none" | thinking: {type: "disabled"} | thinkingBudget: 0 |
| Effort minimal to high | reasoning_effort | reasoning.effort | output_config.effort | thinkingLevel |
| Token budget | refused | refused | thinking.budget_tokens | thinkingBudget |
top_k | refused | refused | top_k | generationConfig.topK |
Known gaps
Some fields have no equivalent in the target format yet. When a request carries one, the gateway doesn’t drop it silently. It answers 400 and names what it could not send, for example 'safetySettings' in the request cannot be translated to another format yet. Sent to a provider of the client’s own format, the same field passes through unchanged.
Examples of what is refused in translation today:
- From a Responses client:
include,truncation,metadata, reasoning settings other than an effort or anautosummary, and built-in tools (web search, file search, computer use, code interpreter, MCP). - From a Gemini client:
safetySettings,cachedContent, Google-run tools such asgoogleSearch, and video parts. - Reasoning and sampling: a token budget or
top_ksent to an OpenAI format, and an effort and a budget together to anything but Anthropic.
Coding agents such as Claude Code, Codex and Gemini CLI rely on vendor-specific fields (thinking, tool shapes, top_k and others). Some of these can’t be translated yet, so don’t expect these agents to work against another vendor’s models through the gateway. To put the gateway in front of Claude Code or Codex with their own vendor, use respan-gateway proxy.
Images
| Format | Endpoint | Vendors that speak it |
|---|---|---|
openai-images | POST /v1/images/generations, POST /v1/images/edits | OpenAI, xAI, Together |
gemini-images | POST /v1beta/models/{model}:generateContent | Gemini |
gemini-images shares its path with gemini-generate. A Gemini client’s call is treated as an image request only when its model routes to an image provider that can’t take generateContent, such as OpenAI. Gemini’s own image models are asked as chats, as Gemini clients expect.
Gemini draws only certain aspect ratios. A size is mapped to the nearest one within 5%, or refused with 400. A mask is refused.
Audio and embeddings
| Format | Endpoint | Vendors that speak it |
|---|---|---|
openai-transcriptions | POST /v1/audio/transcriptions, POST /v1/audio/translations | OpenAI, Groq, Mistral |
openai-speech | POST /v1/audio/speech | OpenAI, Groq, Mistral |
openai-embeddings | POST /v1/embeddings | OpenAI, Gemini, Mistral, Together, Fireworks, Ollama, Cloudflare |
Streaming works as OpenAI’s API defines it: transcript.text.* events for transcriptions, speech.audio.* with stream_format: "sse" for speech. Audio and video bytes are relayed as they arrive.
Video
| Format | Endpoint | Vendors that speak it |
|---|---|---|
openai-videos | POST /v1/videos, GET /v1/videos, GET /v1/videos/{id}, DELETE /v1/videos/{id}, GET /v1/videos/{id}/content, POST /v1/videos/{id}/remix | none directly; answered by Gemini’s Veo |
gemini-veo | POST /v1beta/models/{model}:predictLongRunning, GET /v1beta/{operation}, GET /v1beta/files/{id}:download | Gemini |
An OpenAI Videos client makes Veo videos: the gateway turns the job into a Veo operation and serves the content at its own URL, so the client never needs the Google key. Veo can’t remix, delete or list videos, or make thumbnails. Those requests are refused with 400 unsupported.
Realtime
These are WebSocket sessions.
| Format | Endpoint | Vendors that speak it |
|---|---|---|
openai-realtime | GET /v1/realtime (WebSocket) | OpenAI |
gemini-live | GET /ws/google.ai.generativelanguage.v1beta.GenerativeService.BidiGenerateContent (WebSocket) | Gemini |
mistral-realtime | GET /v1/audio/transcriptions/realtime (WebSocket) | Mistral |
responses-ws | GET /v1/responses (WebSocket) | OpenAI |
- OpenAI Realtime ⇄ Gemini Live. An OpenAI Realtime client can talk to a Gemini Live model, and a Gemini Live client to an OpenAI model. Audio is converted between the two (G.711 and PCM, 24 kHz). The model is read from
?model=on the handshake. - Mistral realtime transcription. Mistral only transcribes. It can answer an OpenAI Realtime transcription session (
type: "transcription"), and a Mistral client can transcribe with OpenAI’s or Gemini’s models. A conversation session sent to Mistral is refused. responses-wsis OpenAI’s Responses over a WebSocket. It is not translated, and it needs exactly one provider that speaks it.
Some settings have no equivalent on the other side. For example, Gemini fixes its setup when a session starts, so an OpenAI client’s session.update that changes anything closes the session with code 1008. Settings that don’t change the answer, such as noise reduction or VAD tuning, are dropped.
Decisions
| Format | Endpoint | Vendors that speak it |
|---|---|---|
decisions | POST /v1/decisions, POST /v1/systemone | Respan, TypeSafe |
A typed decision request: {"model", "state", "questions"}, where each question is a noul, choice or score. The answer is {"model", "answers", "usage"}. Both paths take the same request; the gateway calls Respan at /decisions and TypeSafe at /systemone.
Tools (MCP)
| Endpoint | What it serves |
|---|---|
/mcp | Every tool server as one MCP server, tools named server__tool |
/mcp/{name} | One tool server, [tools.{name}], as it is |
These use MCP’s streamable HTTP. They exist only when the config has tool servers. See Tools and MCP.
Other endpoints
| Endpoint | What it does |
|---|---|
GET /v1/models | Every provider’s models, in OpenAI’s list shape. Needs a client key when keys are set. |
GET /v1beta/models, GET /v1beta/models/{model} | The same list in Gemini’s shape, for Gemini SDKs. |
GET /healthz | Answers ok. Needs no client key. |
/ui/ | The web UI, and the admin API under /ui/api/. Off with ui = false. |
respan-gateway proxy does not serve /v1/models or /v1beta/models; the vendor answers them.
Which formats are served
With no formats setting, the gateway serves:
openai-chatandanthropic-messages, always;- every other chat format that at least one provider speaks;
- every image, audio, embedding, video, decision and realtime format whose kind at least one provider speaks;
responses-wsif a provider speaks it;/mcpif there are tool servers.
So with only an Anthropic key, POST /v1/responses and Gemini’s generateContent are not served. List the formats you want at the top of gateway.toml to serve them anyway:
formats = ["openai-chat", "openai-responses", "anthropic-messages", "gemini-generate"]One more format, passthrough, relays every request the other formats don’t take, unread, to the one provider that speaks passthrough. It must come last in formats. respan-gateway proxy uses it.
Which formats each vendor speaks, and its base URLs, is on Providers and models.