# Create a chat completion

> POST /v1/chat/completions on BigModel.io. OpenAI Chat Completions for GLM, DeepSeek, Kimi, MiniMax and more, with streaming, tools and OpenRouter-style fallbacks.

Web version: https://bigmodel.io/docs/api-chat-completions · Updated 2026-10-18

`POST https://bigmodel.io/v1/chat/completions`

The OpenAI Chat Completions endpoint. Every key group that serves text models can call it, including chat-only groups (DeepSeek, GLM platforms). On chat-only groups the body goes to the provider unchanged; on other groups it is converted and some fields are dropped (see Notes below).

## Request

```http
POST https://bigmodel.io/v1/chat/completions
```

### Authentication

| Header | Value |
|---|---|
| `Authorization` | `Bearer $BIGMODEL_API_KEY` |
| `x-api-key` | `$BIGMODEL_API_KEY` |

Send one of these.

### Body

Standard OpenAI Chat Completions body. For GLM, DeepSeek and Qwen groups the body is passed to the provider as is (only `model` is rewritten), so support for each field depends on the model. Other groups convert the request, and `response_format`, `n`, `seed`, `user` and `logprobs` are dropped there.

| Field | Type | Required | Description |
|---|---|---|---|
| `model` | string | Yes | Model ID from the catalog, e.g. `glm-5.3`. OpenRouter-style names such as `z-ai/glm-5.3` are resolved too. |
| `models` | array<string> |  | Fallback models tried in order after `model` (at most 5 attempts in total). Removed before forwarding. |
| `messages` | array<ChatMessage> | Yes | The conversation so far. |
| `messages[].role` | string | Yes | Who wrote the message. One of: `system`, `developer`, `user`, `assistant`, `tool` |
| `messages[].content` | string \| array<object> | Yes | Text, or an array of content parts (`text`, `image_url`) for models that accept images. |
| `messages[].tool_calls` | array<object> |  | Tool calls made by the assistant in an earlier turn. |
| `messages[].tool_call_id` | string |  | For `tool` messages: the call this result answers. |
| `stream` | boolean |  | Stream the reply as server-sent events. Default `false` |
| `stream_options` | object |  | Stream options. Usage is always requested from the upstream. |
| `stream_options.include_usage` | boolean |  |  |
| `max_tokens` | integer |  | Maximum tokens to generate. |
| `max_completion_tokens` | integer |  | Newer name for `max_tokens`. |
| `temperature` | number |  | Sampling temperature. |
| `top_p` | number |  | Nucleus sampling. |
| `stop` | string \| array<string> |  | Stop sequences. |
| `tools` | array<object> |  | Function tools the model may call. |
| `tool_choice` | string \| object |  | `auto`, `none`, `required`, or a specific function. |
| `response_format` | object |  | JSON mode or JSON schema, where the model supports it. Passed through on GLM, DeepSeek and Qwen groups; dropped on groups that convert the request. |
| `reasoning_effort` | string |  | Reasoning effort for models that support it. |

## Response

| Status | Meaning |
|---|---|
| `200` | A chat completion, or an SSE stream when `stream` is true. |
| `400` | `api_key_in_query_deprecated` (key sent in the query string), or `invalid_request_error`: empty or invalid JSON, missing `model`, a non-boolean `stream`, or another malformed field. |
| `401` | `API_KEY_REQUIRED`, `INVALID_API_KEY`, `API_KEY_DISABLED`, `USER_NOT_FOUND`, `USER_INACTIVE`. |
| `403` | `INSUFFICIENT_BALANCE`, `API_KEY_EXPIRED`, `ACCESS_DENIED` (IP rule), `SUBSCRIPTION_NOT_FOUND`, `SUBSCRIPTION_INVALID`, or a `permission_error` (key without a group, endpoint not allowed for the group). |
| `413` | Request body too large. |
| `429` | `API_KEY_QUOTA_EXHAUSTED`, `USAGE_LIMIT_EXCEEDED` (plan limit), or `rate_limit_exceeded` / `rate_limit_error` (key 5h/1d/7d limit, requests per minute, concurrency, upstream). RPM limits send `Retry-After`. |
| `502` | `upstream_error`: the model provider failed. |
| `503` | `api_error` and similar: no capacity for this model in your group right now, or the model is not served by your group (`No available accounts`). |

### Response fields

| Field | Type | Description |
|---|---|---|
| `id` | string |  |
| `object` | any |  |
| `created` | integer |  |
| `model` | string | The model that answered. |
| `choices` | array<object> |  |
| `choices[].index` | integer |  |
| `choices[].message` | ChatMessage |  |
| `choices[].finish_reason` | string | `stop`, `length`, `tool_calls`, … |
| `usage` | object |  |
| `usage.prompt_tokens` | integer |  |
| `usage.completion_tokens` | integer |  |
| `usage.total_tokens` | integer |  |

With `stream: true` the response is a server-sent event stream of `chat.completion.chunk` objects ending with `data: [DONE]`. The gateway asks the upstream for a final usage chunk.


## Examples

```bash [cURL]
curl https://bigmodel.io/v1/chat/completions \
  -H "Authorization: Bearer $BIGMODEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "glm-5.3",
    "messages": [
      {"role": "system", "content": "You are a concise assistant."},
      {"role": "user", "content": "Explain HTTP 429 in one sentence."}
    ],
    "max_tokens": 128
  }'
```

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

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

resp = client.chat.completions.create(
    model="glm-5.3",
    messages=[
        {"role": "system", "content": "You are a concise assistant."},
        {"role": "user", "content": "Explain HTTP 429 in one sentence."},
    ],
    max_tokens=128,
)
print(resp.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 resp = await client.chat.completions.create({
  model: 'glm-5.3',
  messages: [
    {role: 'system', content: 'You are a concise assistant.'},
    {role: 'user', content: 'Explain HTTP 429 in one sentence.'},
  ],
  max_tokens: 128,
})
console.log(resp.choices[0].message.content)
```

Example response (the `id`, timestamps, text and token counts are illustrative; extra fields such as `reasoning_content` come from the model provider):

```json
{
  "id": "chatcmpl-...",
  "object": "chat.completion",
  "created": 1792310400,
  "model": "glm-5.3",
  "choices": [
    {
      "index": 0,
      "message": {"role": "assistant", "content": "HTTP 429 means you sent too many requests in a given time and should retry later."},
      "finish_reason": "stop"
    }
  ],
  "usage": {"prompt_tokens": 24, "completion_tokens": 19, "total_tokens": 43}
}
```

### Streaming

```bash [cURL]
curl -N https://bigmodel.io/v1/chat/completions \
  -H "Authorization: Bearer $BIGMODEL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"glm-5.3","stream":true,"messages":[{"role":"user","content":"Count to 3."}]}'
```

```python [Python]
stream = client.chat.completions.create(
    model="glm-5.3",
    messages=[{"role": "user", "content": "Count to 3."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
```

```js [Node.js]
const stream = await client.chat.completions.create({
  model: 'glm-5.3',
  messages: [{role: 'user', content: 'Count to 3.'}],
  stream: true,
})
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? '')
```

The stream ends with `data: [DONE]`. The last data chunk usually carries `usage` and an empty `choices` array, so skip chunks without choices, as above.

### Fallback models

```json
{
  "model": "glm-5.3",
  "models": ["kimi-k3", "deepseek-v4-pro"],
  "messages": [{"role": "user", "content": "Hello"}]
}
```

The gateway tries `glm-5.3`, then the `models` entries in order. See [OpenRouter compatibility](https://bigmodel.io/docs/openrouter-compat).

## Notes

- **Field support depends on the group.** On chat-only groups (DeepSeek, GLM platforms) only `model` is rewritten; `tools`, `tool_choice`, `response_format`, `thinking`, `reasoning_effort` and image input pass through, and support depends on the model. On other OpenAI groups and on Anthropic groups the request is converted, and only `model`, `messages`, `instructions`, `max_tokens`, `max_completion_tokens`, `temperature`, `top_p`, `stream`, `stream_options.include_usage`, `tools`, `tool_choice`, `reasoning_effort`, `service_tier`, `stop`, `functions` and `function_call` survive. **`response_format`, `n`, `seed`, `user` and `logprobs` are dropped** on those paths, so JSON mode is not enforced there. See [Structured output](https://bigmodel.io/docs/structured-output).
- **Unknown model → `503`, not `404`.** A model your group does not serve, or a typo, returns `503` `api_error` "No available accounts: no available accounts supporting model: …". Copy IDs from [/models](https://bigmodel.io/models) or [`GET /v1/models`](https://bigmodel.io/docs/api-models).
- **OpenRouter-style requests.** `z-ai/glm-5.3` and suffixes like `:nitro` are resolved to a served model where possible; `:free` is never stripped. `models` allows at most 5 attempts in total; fallback happens on `404`, `408`, `429` and `5xx` before any bytes are sent, never on `400`/`401`/`402`/`403`/`413`. You pay only for the attempt that succeeds. `provider`, `transforms` and `route` are ignored.
- **Streaming usage.** The gateway always requests usage from the upstream, so the final chunk has token counts even if you did not set `stream_options`. Errors after the stream starts arrive as an SSE `error` event.
- **Bad JSON, an empty body or a missing `model`** returns `400` `invalid_request_error`.
- Full error list: [Errors](https://bigmodel.io/docs/errors).

## Related

- [Streaming](https://bigmodel.io/docs/streaming)
- [Tool calling](https://bigmodel.io/docs/tool-calling)
- [Image input](https://bigmodel.io/docs/vision)
- [OpenAI SDK](https://bigmodel.io/docs/openai-sdk-langchain)
