# OpenRouter compatibility

> Which OpenRouter conventions BigModel.io supports. provider/model names, routing suffixes, the models fallback array, HTTP-Referer and X-Title, and what is ignored.

Web version: https://bigmodel.io/docs/openrouter-compat · Updated 2026-10-18

BigModel.io understands the main OpenRouter request conventions on `/v1/chat/completions`, `/v1/messages` and `/v1/responses`. This page is the exact reference; for a step-by-step switch, see [Migrate from OpenRouter](https://bigmodel.io/docs/migrate-from-openrouter).

| OpenRouter feature | On BigModel.io |
|---|---|
| `provider/model` IDs, e.g. `z-ai/glm-5.3` | Supported: resolved to a model your group serves |
| Routing suffixes `:nitro`, `:floor`, `:exacto` | Removed if the exact name is not served |
| `:free` suffix | Kept; never removed |
| `models` fallback array | Supported, up to 5 models per request |
| `HTTP-Referer`, `X-Title`, `X-OpenRouter-Title` | Recorded for app attribution |
| `provider` object, `transforms`, `route` | **Not supported** |

## How model names are resolved

Plain names without `/` or `:` (such as `glm-5.3`) are used as they are. For other names, the gateway checks whether your key's group explicitly serves the name, then tries these variants in order and uses the first one served:

1. The exact name: `z-ai/glm-5.3:nitro`
2. Without the routing suffix: `z-ai/glm-5.3`
3. Without the `provider/` prefix as well: `glm-5.3`
4. Step 2 with dots replaced by dashes: `z-ai/glm-5-3`
5. Step 3 with dots replaced by dashes: `glm-5-3`

Details:

- Only `:nitro`, `:floor` and `:exacto` are removed, case-insensitively. A `:free` request is never served by a paid model.
- Only a single `provider/` prefix is removed. A name with two slashes keeps its prefix.
- "Served" means the group lists the model or has a price for it.
- If nothing matches, the original name is sent on, and you get the normal unknown-model error: 503 `api_error` "No available accounts". See [Model IDs](https://bigmodel.io/docs/model-ids).

## Fallback with the models array

`models` is an ordered list of models to try if `model` fails.

```bash [cURL]
curl https://bigmodel.io/v1/chat/completions \
  -H "Authorization: Bearer $BIGMODEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "kimi-k3",
    "models": ["glm-5.3", "deepseek-v4-pro"],
    "messages": [{"role": "user", "content": "Summarize this diff."}]
  }'
```

```python [Python]
import os
from openai import OpenAI

client = OpenAI(base_url="https://bigmodel.io/v1", api_key=os.environ["BIGMODEL_API_KEY"])

completion = client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Summarize this diff."}],
    extra_body={"models": ["glm-5.3", "deepseek-v4-pro"]},
)
print(completion.model, completion.choices[0].message.content)
```

```js [Node.js]
import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://bigmodel.io/v1", apiKey: process.env.BIGMODEL_API_KEY });

const completion = await client.chat.completions.create({
  model: "kimi-k3",
  models: ["glm-5.3", "deepseek-v4-pro"],
  messages: [{ role: "user", content: "Summarize this diff." }],
});
console.log(completion.model, completion.choices[0].message.content);
```

The rules:

- **Candidates.** `model` first, then `models` in order. Duplicates are skipped, non-string entries are ignored, and at most **5** candidates are tried in total; the rest are dropped. Each candidate is name-resolved as above.
- **When the next model is tried.** Only when an attempt fails with **404, 408, 429 or any 5xx** before any response bytes are sent.
- **When it is not.** 400, 401, 402, 403 and 413 are returned right away, because they would fail for every model. Once any byte has been sent, including an SSE keep-alive ping, the response is committed and no other model is tried.
- **If every candidate fails.** You get the last candidate's error.
- **Forwarding.** The `models` field is removed before the request goes upstream.
- **Billing.** You are charged only for the attempt that succeeds.

## App attribution headers

Send `HTTP-Referer` (your app's URL) and `X-Title` (its name) as on OpenRouter. `X-OpenRouter-Title` is accepted when `X-Title` is absent. They do not change routing or price. What is recorded: [App attribution](https://bigmodel.io/docs/app-attribution).

## What is not supported

- **`provider` object** (`order`, `allow_fallbacks`, `only`, `ignore`, `sort`, price limits and so on). Not interpreted. Your key's group decides which upstream serves the model.
- **`transforms`** (for example `middle-out`). Not interpreted; long prompts are not compressed for you.
- **`route`** (for example `"fallback"`). Not interpreted; use the `models` array.

Remove these fields. On GLM and DeepSeek groups the request body is forwarded unchanged apart from `model`, so a provider may reject unknown fields.

Other OpenRouter-only features, such as its credits endpoints or generation lookups, do not exist on BigModel.io. Use [GET /v1/usage](https://bigmodel.io/docs/api-usage) for key usage and the [Usage](https://bigmodel.io/usage) page for per-request records.

## Verify the setup

Send the fallback example with a deliberately wrong first model, for example `"model": "kimi-k3-typo"`. The request should still succeed, and in [Usage](https://bigmodel.io/usage) the request should show `glm-5.3` (the first fallback) as its model, with only the successful attempt charged.

## Troubleshooting

**503 "No available accounts" with a `provider/model` name.** None of the variants is served by your key's group. Use the plain ID from the [catalog](https://bigmodel.io/models).

**Fallback does not happen.** The first model failed with a code that does not trigger fallback (400, 401, 402, 403, 413), or the stream had already started. Check the status code.

**Only some fallback models are tried.** At most 5 candidates are used, counting `model`. Shorten the list.

**400 mentioning `provider`, `transforms` or `route`.** The upstream rejected a field BigModel.io does not interpret. Remove it.

**A `:free` model is not found.** `:free` is never stripped. Use an ID that exists in the catalog.

## Related

- [Migrate from OpenRouter](https://bigmodel.io/docs/migrate-from-openrouter) for the base URL and key switch.
- [Model IDs](https://bigmodel.io/docs/model-ids) and [App attribution](https://bigmodel.io/docs/app-attribution).
- [Chat Completions API reference](https://bigmodel.io/docs/api-chat-completions).
