---
title: "API formats"
subtitle: "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. The [`responses` plugin](/docs/oss-gateway/plugins#responses) 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 an `auto` summary, and built-in tools (web search, file search, computer use, code interpreter, MCP).
- From a Gemini client: `safetySettings`, `cachedContent`, Google-run tools such as `googleSearch`, and video parts.
- Reasoning and sampling: a token budget or `top_k` sent to an OpenAI format, and an effort and a budget together to anything but Anthropic.

<Warning>
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`](/docs/oss-gateway/cli#proxy).
</Warning>

## 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-ws`** is 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](/docs/oss-gateway/tools).

## 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-chat` and `anthropic-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-ws` if a provider speaks it;
- `/mcp` if 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:

```toml
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](/docs/oss-gateway/providers).
