Gateway API
A single OpenAI-compatible endpoint that routes to 500+ models across 60+ providers. Drop it in wherever you already use the OpenAI SDK — no other changes required.
Base URL
https://getmegabrain.com/api/gateway
Authentication
All requests must include your API key as a Bearer token in the Authorization header. You can find your key on the Profile page after signing in.
curl https://getmegabrain.com/api/gateway/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}]}'Free models can be used without authentication, subject to rate limits.
Chat Completions
Fully compatible with the OpenAI Chat Completions API. Both streaming and non-streaming modes are supported.
Example — non-streaming
curl https://getmegabrain.com/api/gateway/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-3-5-sonnet",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
]
}'Example — streaming
curl https://getmegabrain.com/api/gateway/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-3-5-sonnet",
"stream": true,
"messages": [{"role": "user", "content": "Tell me a joke"}]
}'Example — OpenAI SDK
import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://getmegabrain.com/api/gateway",
});
const response = await client.chat.completions.create({
model: "anthropic/claude-3-5-sonnet",
messages: [{ role: "user", content: "Hello!" }],
});
console.log(response.choices[0].message.content);Auto Model
Set model to one of the Auto Model IDs to let the Gateway choose the best model for each request.
| Model ID | Description |
|---|---|
| mb-auto/frontier | Highest performance, tuned for agentic coding |
| mb-auto/free | Routes only to free models |
Response
The OpenAI Chat Completions shape, plus provider (the serving upstream), native_finish_reason, and a usage object with cost (USD actually charged), is_byok and cached / reasoning token details. Every reply carries an X-Generation-Id header you can look up at GET /v1/generation?id=. Streams end with exactly one usage chunk and data: [DONE].
Parameters
Every field of the Chat Completions request the gateway accepts, and what it does with it. “Forwarded” fields reach the model unchanged — whether the model honours them is what its supported_parameters in GET /v1/models says.
| Parameter | Type | Range | Handling | Description |
|---|---|---|---|---|
| model * | string | Handled by the gateway | Catalogue model id (`GET /models`), e.g. `anthropic/claude-fable-5.1`, `openai/gpt-6-astra`, `mb-auto/frontier`, or a preset reference (`@preset/<slug>`, `<model>@preset/<slug>`). Routing variant suffixes (`:nitro`, `:floor`, `:exacto`, `:batch`, `:online`, `:thinking`, `:extended`) are stripped; `openrouter/auto` resolves to `mb-auto/frontier`. | |
| messages * | array | Forwarded to the model | The conversation, OpenAI Chat Completions shape (`system`, `developer`, `user`, `assistant`, `tool` roles; text, image, file and audio parts). | |
| models | string[] | up to 8 ids | Handled by the gateway | Fallback models tried in order after `model` fails upstream with any 4xx/5xx; the reply `model` and the price are those of the model that served. Suppressed by `provider.allow_fallbacks: false`. |
| preset | string | Handled by the gateway | A saved preset (`POST /presets`): `@preset/<slug>` or the bare slug. Also expressible as `model: "@preset/<slug>"` or `model: "<model>@preset/<slug>"`. Request fields override the preset’s; the preset fills the rest (model, parameters, provider, system prompt; tools are unioned). | |
| stream | boolean | (default false) | Handled by the gateway | Server-sent events. A stream ends with exactly one usage chunk and `data: [DONE]`; `: MEGABRAIN PROCESSING` comment lines keep the connection warm. |
| stream_options | object | Set by the gateway | `include_usage` is always set to `true`; usage is returned on every stream. | |
| max_tokens | integer | ≥ 1 | Forwarded to the model | Maximum completion tokens. Rewritten to `max_completion_tokens` for OpenAI-served models that no longer accept `max_tokens`. |
| max_completion_tokens | integer | ≥ 1 | Forwarded to the model | Maximum completion tokens (OpenAI naming); takes precedence over `max_tokens`. |
| temperature | number | 0 – 2 | Forwarded to the model | Sampling temperature. |
| top_p | number | 0 – 1 | Forwarded to the model | Nucleus sampling. |
| top_k | integer | ≥ 0 | Forwarded to the model | Sample from the K most likely tokens; not every model supports it. |
| min_p | number | 0 – 1 | Forwarded to the model | Minimum probability relative to the most likely token; not every model supports it. |
| top_a | number | 0 – 1 | Forwarded to the model | Top-A sampling; not every model supports it. |
| frequency_penalty | number | -2 – 2 | Forwarded to the model | Penalises tokens by how often they already appeared. |
| presence_penalty | number | -2 – 2 | Forwarded to the model | Penalises tokens that already appeared at all. |
| repetition_penalty | number | 0 – 2 (default 1) | Forwarded to the model | Multiplicative repetition penalty (1 = none); not every model supports it. |
| seed | integer | Forwarded to the model | Best-effort deterministic sampling. | |
| stop | string | string[] | up to 4 | Forwarded to the model | Stop sequences. |
| logit_bias | object | Forwarded to the model | Token id → bias (-100 – 100). | |
| logprobs | boolean | Forwarded to the model | Return token log probabilities. | |
| top_logprobs | integer | 0 – 20 | Forwarded to the model | Number of top log probabilities per token (needs `logprobs: true`). |
| response_format | object | Forwarded to the model | `{ "type": "text" | "json_object" | "json_schema", "json_schema": { … } }`. Check `structured_outputs` in the model's `supported_parameters` before relying on `json_schema`. | |
| tools | array | Forwarded to the model | Function tools (`{ "type": "function", "function": { … } }`). Tools with an empty name are removed. | |
| tool_choice | string | object | Forwarded to the model | `none`, `auto`, `required`, or `{ "type": "function", "function": { "name": … } }`. | |
| parallel_tool_calls | boolean | Forwarded to the model | Allow several tool calls in one reply. | |
| prediction | object | Forwarded to the model | Predicted output (`{ "type": "content", "content": … }`) for models that support it. | |
| modalities | string[] | Forwarded to the model | Requested output modalities (`text`, `image`, `audio`) for models that support them. | |
| image_config | object | Forwarded to the model | Image-output options for image-capable models. | |
| cache_control | object | Forwarded to the model | Request-level prompt-cache directive for providers that support explicit caching. | |
| reasoning | object | Forwarded to the model | `{ "effort": "max" | "xhigh" | "high" | "medium" | "low" | "minimal" | "none", "max_tokens": n, "exclude": bool, "enabled": bool }`. Check `reasoning` in the model record for supported efforts. | |
| reasoning_effort | string | max | xhigh | high | medium | low | minimal | none | Forwarded to the model | Shorthand for `reasoning.effort`. |
| include_reasoning | boolean | Forwarded to the model | Return reasoning content alongside the answer (legacy form of `reasoning.exclude: false`). | |
| provider | object | Handled by the gateway | `allow_fallbacks` (false suppresses `models[]` and the routing chain), `data_collection: "deny"` and `zdr: true` are honoured; `order`, `only`, `ignore` apply to BYOK and direct-gateway providers; `require_parameters`, `max_price`, `sort`, `quantizations`, `preferred_*`, `enforce_distillable_text` are accepted and not enforced yet. | |
| route | string | Accepted and ignored | Deprecated alias of `provider.sort`; accepted and ignored. | |
| plugins | array | Handled by the gateway | OpenRouter plugins. `{id: "file-parser", pdf: {engine}}` is honoured: `pdf-text` extracts the text of `file` / `input_file` / `document` PDF attachments at the gateway (free) and sends it as text, `native` sends the PDF to the model; without the plugin, models with native PDF input get the file and every other model gets the text. `mistral-ocr` is not offered (400). Other plugins (`web`, `context-compression`, …) are accepted and ignored. | |
| transforms | string[] | Accepted and ignored | `["middle-out"]` is recorded on the usage row and not applied. | |
| usage | object | Accepted and ignored | `{ "include": true }` is a no-op: usage is always returned. | |
| session_id | string | ≤ 256 chars | Handled by the gateway | Sticky-routing / grouping key, recorded on the usage row (aliases: `x-session-id`, `x-kilo-session` headers). |
| user | string | ≤ 256 chars | Recorded, not forwarded | Your end-user id. Stored on the usage row (`GET /generation` → `external_user`) and forwarded to the upstream as sent; when absent the gateway sends its own hashed identity. |
| metadata | object | ≤ 16 pairs, 64-char keys, 512-char values | Recorded, not forwarded | Free-form string tags stored on the usage row (`GET /generation` → `metadata`); not sent upstream. 400 when over the limits. |
| prompt_cache_key | string | Set by the gateway | Replaced by a hash of your session id when one is present (per-session prompt caching). | |
| safety_identifier | string | Set by the gateway | Replaced by the gateway's hashed identity for the calling account. | |
| service_tier | string | Accepted and ignored | Accepted and ignored. | |
| trace | object | Accepted and ignored | Accepted and ignored. | |
| debug | object | Accepted and ignored | Accepted and ignored. | |
| web_search_options | object | Accepted and ignored | Accepted and ignored (web search is not offered yet). | |
| prompt_cache_options | object | Accepted and ignored | Accepted and ignored. | |
| stop_server_tools_when | object | Accepted and ignored | Accepted and ignored (no server tools yet). |
* required
Embeddings
Generate vector embeddings from text. Compatible with the OpenAI Embeddings API.
curl https://getmegabrain.com/api/gateway/embeddings \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "text-embedding-3-small",
"input": "The quick brown fox"
}'import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://getmegabrain.com/api/gateway",
});
const result = await client.embeddings.create({
model: "text-embedding-3-small",
input: "The quick brown fox",
});
console.log(result.data[0].embedding);Audio
Speech to text and text to speech, in OpenAI's shapes, so the OpenAI SDK's audio.transcriptions and audio.speech work against the same base URL. Audio models are their own set, not catalogue models — GET /v1/audio/models lists them. An upload is at most 4 MiB, and both routes need a gateway key: there is no anonymous tier for audio.
curl https://getmegabrain.com/api/gateway/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-F file=@meeting.mp3 \
-F model=openai/whisper-1curl https://getmegabrain.com/api/gateway/audio/speech \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-o speech.mp3 \
-d '{
"model": "openai/gpt-4o-mini-tts",
"input": "One API, every model.",
"voice": "onyx"
}'List Models
Retrieve the list of models available through the Gateway. The response follows the OpenAI models format.
curl https://getmegabrain.com/api/gateway/models \
-H "Authorization: Bearer YOUR_API_KEY"{
"data": [
{
"id": "anthropic/claude-fable-5.1",
"canonical_slug": "anthropic/claude-fable-5.1",
"name": "Anthropic: Claude Fable 5.1",
"context_length": 1000000,
"architecture": { "modality": "text+image->text", "input_modalities": ["text", "image"], ... },
"pricing": { "prompt": "0.000005", "completion": "0.000025", ... },
"supported_parameters": ["max_tokens", "reasoning", "tools", ...],
"reasoning": { "supported_efforts": ["max", "high", "low"], ... }
},
...
],
"total_count": 445,
"links": { "next": "/api/gateway/v1/models?offset=100&limit=100" }
}Filter and page with query parameters: offset, limit (≤ 1000), q, supported_parameters, input_modalities, output_modalities, providers, arch, context, min_price / max_price (USD per million prompt tokens), min_output_price / max_output_price, zdr, max_age_days, min_bench (0–100 Terminal-Bench), sort (newest, pricing-low-to-high, pricing-high-to-low, context-high-to-low, bench-high-to-low). total_count is the size of the filtered set before paging. The public models page offers the same filters as facets and mirrors them into its query string.
Keys, credits, generations
Everything else the gateway serves on the same base URL. Named keys (mb-v1-…) carry their own spend limit and reset window; a management key can create keys and read credits but cannot call inference.
| POST | /v1/completions | Legacy text completions (prompt → choices[].text), same models and parameters |
| POST | /v1/responses | OpenAI Responses API, same models |
| POST | /v1/messages | Anthropic Messages API (also /api/anthropic/v1 with x-api-key) |
| GET | /v1/models/count | Count of the (filtered) catalogue |
| GET | /v1/models/user | The catalogue as your key sees it (401 when anonymous) |
| GET | /v1/generation?id= | Receipt for one request: tokens, cost, latency, app, user |
| POST | /v1/generation/feedback | Report feedback on a generation: category + comment |
| GET | /v1/key | The calling key: label, limits, usage |
| POST | /v1/auth/keys | OAuth PKCE: exchange the code from /auth?callback_url&code_challenge for an inference key |
| GET | /v1/credits | Balance and usage (management keys) |
| GET | /v1/keys | List named keys (management keys) |
| POST | /v1/keys | Create a named key with a spend limit; plaintext returned once |
| PATCH | /v1/keys/{id} | Rename, disable, change limits |
| DELETE | /v1/keys/{id} | Revoke |
| GET | /v1/activity | Daily usage per model and upstream, last 30 days (management keys) |
| GET | /v1/byok | List BYOK credentials (management keys) |
| POST | /v1/byok | Store a provider key: provider + key |
| PATCH | /v1/byok/{id} | Replace the key, enable / disable |
| DELETE | /v1/byok/{id} | Remove a BYOK credential |
| GET | /v1/model/{author}/{slug} | One catalogue entry |
| GET | /v1/notifications | Low-balance alert threshold and the channels alerts go to: email, signed webhook, Slack |
| PATCH | /v1/notifications | Set the threshold (USD or null) and / or the channels |
| GET | /v1/notifications/deprecations | Retiring models you used in the last 30 days, with when you were notified |
| GET | /v1/privacy | Personal privacy toggles: data collection, training on paid / free models |
| PATCH | /v1/privacy | Change them; models that may train are hidden and refused when off |
| GET | /v1/presets | List presets (management keys) |
| POST | /v1/presets | Create a preset; use it as model: "@preset/<slug>" |
| PATCH | /v1/presets/{slug} | Rename, describe, or publish a new config version |
| DELETE | /v1/presets/{slug} | Delete a preset |
| GET | /v1/broadcast/destinations | Broadcast: where generation traces are exported (management keys) |
| POST | /v1/broadcast/destinations | Add a webhook or OpenTelemetry collector: url, headers, secret, sampling, key filters |
| PATCH | /v1/broadcast/destinations/{id} | Change any field |
| DELETE | /v1/broadcast/destinations/{id} | Remove a destination |
| POST | /v1/broadcast/destinations/{id}/test | Send a synthetic trace now |
| GET | /v1/guardrails | Guardrails: budget + model/provider/privacy policy (management keys) |
| POST | /v1/guardrails | Create a guardrail: budget, allowed/ignored models and providers, privacy, assignments |
| PATCH | /v1/guardrails/{id} | Change any field |
| DELETE | /v1/guardrails/{id} | Remove a guardrail |
| POST | /v1/guardrails/{id}/assignments | Cover an account, member or key scope |
| GET | /v1/datasets/rankings-daily | Public: top models per UTC day by tokens |
| GET | /v1/datasets/app-rankings | Public: attributed apps by tokens (?model narrows) |
| GET | /v1/datasets/session-cost | Public: sessions and spend per session per model |
| GET | /v1/files | Files API: uploaded files and the storage quota |
| POST | /v1/files | Upload (multipart or JSON file_data, ≤ 4 MiB) or reserve a presigned upload; use the id as file_id in a file part |
| GET | /v1/files/{id} | One file |
| GET | /v1/files/{id}/content | Its bytes |
| POST | /v1/files/{id}/complete | Confirm a presigned upload |
| DELETE | /v1/files/{id} | Delete a file |
| POST | /v1/analytics/query | Usage analytics: metrics × dimensions × granularity, with filters (management keys) |
| GET | /v1/analytics/meta | The analytics metrics, dimensions and limits |
curl -X POST https://getmegabrain.com/api/gateway/v1/keys \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "ci-runner", "limit": 25, "limit_reset": "monthly"}'Errors
Every error, on every endpoint, uses the OpenRouter envelope: error.code equals the HTTP status, error.message is human-readable, error.metadata.error_type is the canonical class (invalid_request, authentication, payment_required, permission_denied, not_found, rate_limit_exceeded, provider_unavailable, …) and error.metadata.megabrain_error_type the precise reason below. Upstream failures also carry provider_code and raw. A failure after a stream has started arrives as a final chunk with an error object and finish_reason: "error".
{
"error": {
"code": 402,
"message": "API key has reached its spend limit",
"metadata": {
"error_type": "payment_required",
"megabrain_error_type": "insufficient_credits",
"reason": "api_key_over_limit"
}
},
"error_type": "insufficient_credits"
}| Status | megabrain_error_type | error_type | When |
|---|---|---|---|
| 400 | invalid_request | invalid_request | Malformed JSON, a missing required field, or a value outside its documented limits (`user`, `metadata`, …). |
| 400 | api_kind_not_supported | invalid_request | The model cannot be served on this API (chat / responses / messages). |
| 400 | context_length_exceeded | context_length_exceeded | The prompt is longer than the model's context window. |
| 400 | unsupported_field | invalid_request | A field is not supported on this endpoint. |
| 400 | missing_client_ip | invalid_request | The client IP could not be determined. |
| 401 | authentication_required | authentication | Missing, invalid, disabled or expired API key (`error.metadata.reason` says which), or the wrong key class for the endpoint (403). |
| 401 | paid_model_auth_required | authentication | A paid model needs an API key; only free models are anonymous. |
| 402 | usage_limit_exceeded | payment_required | The organization's or account's configured usage limit is reached. |
| 402 | insufficient_credits | payment_required | The account balance, or the API key spend limit, is exhausted. |
| 403 | upgrade_required | permission_denied | The request needs a plan the account does not have. |
| 403 | data_collection_required | permission_denied | The model needs data collection the organization has denied. |
| 403 | model_not_allowed | permission_denied | The organization's model policy does not allow this model. |
| 403 | feature_exclusive_model | permission_denied | The model is only available to a specific product feature. |
| 403 | provider_not_allowed | permission_denied | The `provider` preferences leave no provider the organization's policy allows. |
| 403 | byok_key_required | permission_denied | This model is only served with your own provider key. |
| 403 | abuse_blocked | permission_denied | The request was blocked by abuse prevention rules. |
| 404 | invalid_path | not_found | Unknown endpoint on the gateway prefix. |
| 404 | discontinued_free_model | not_found | This free model is no longer served. |
| 404 | model_not_found | not_found | No catalogue model with this id. |
| 404 | unsupported_fim_model | not_found | Not a fill-in-the-middle model. |
| 404 | unsupported_edit_model | not_found | Not an edit-completions model. |
| 404 | generation_not_found | not_found | No generation with this id for the caller (`GET /generation`). |
| 429 | rate_limit_exceeded | rate_limit_exceeded | Free-model rate limit reached; `error.metadata` carries the window. |
| 429 | promotion_limit_reached | rate_limit_exceeded | The anonymous free-model allowance is used up; sign in to continue. |
| 429 | mpass_limit_reached | rate_limit_exceeded | The subscription's usage window is exhausted; `error.metadata.resets_at` says when. |
| 502 | byok_error | provider_unavailable | Your own provider key was refused upstream. |
| 502 | upstream_error | provider_unavailable | The upstream returned an error; `error.metadata.provider_code` and `raw` carry its status and body. The status mirrors the upstream when it is meaningful (e.g. 429). |
| 503 | temporarily_unavailable | provider_unavailable | The model or its upstream is unavailable right now; retry with backoff. |
| 503 | no_free_models_available | provider_unavailable | The free tier has no model available for this request right now. |
OpenAPI
The whole contract — every endpoint, the request and response schemas, the parameter and error references above — is published as an OpenAPI 3.1 document, generated from the same source as this page. Point a client generator or an API explorer at it.
MCP server
The catalogue and this reference are also served over the Model Context Protocol, so an agent can look a model up or read a parameter's range without a browser and without anyone pasting documentation into a prompt. Four read-only tools: search_models, get_model, list_providers and gateway_reference. No key: it answers from the public catalogue and never sees your usage or spend.
Ready to start?
Create a free account and get your API key in 2 minutes.
Get started free