Use the OpenAI SDK for Python and Node.js with BigModel.io

Call GLM, Kimi, DeepSeek and MiniMax models from the official OpenAI Python and Node.js SDKs by setting base_url to https://bigmodel.io/v1. Streaming, tools and fixes.

On this page
  1. Install
  2. Minimal call
  3. Streaming
  4. Tool calling
  5. Reasoning output
  6. Responses API
  7. Verify the setup
  8. LangChain
  9. OpenRouter-style requests
  10. Troubleshooting
  11. Related

BigModel.io speaks the OpenAI Chat Completions protocol, so the official OpenAI SDKs work after you change two values: the base URL and the API key.

Setting Value
Base URL https://bigmodel.io/v1
API key your BigModel.io key (sk-...), from an environment variable
Model a model ID from the model catalog, e.g. glm-5.3

Which models a key can call depends on the key's group. All examples read the key from BIGMODEL_API_KEY:

bash
export BIGMODEL_API_KEY="sk-..."

#Install

Python
pip install openai
Node.js
npm install openai

#Minimal call

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="glm-5.3",
    messages=[{"role": "user", "content": "Explain vector databases in three sentences."}],
)
print(completion.choices[0].message.content)
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: "glm-5.3",
  messages: [{ role: "user", content: "Explain vector databases in three sentences." }],
});
console.log(completion.choices[0].message.content);

Both SDKs also read OPENAI_BASE_URL and OPENAI_API_KEY when you pass no arguments. That moves existing code without edits, but it also redirects every other OpenAI client in the same process.

#Streaming

Python
stream = client.chat.completions.create(
    model="glm-5.3",
    messages=[{"role": "user", "content": "Write a haiku about latency."}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
Node.js
const stream = await client.chat.completions.create({
  model: "glm-5.3",
  messages: [{ role: "user", content: "Write a haiku about latency." }],
  stream: true,
});
for await (const part of stream) {
  process.stdout.write(part.choices[0]?.delta?.content || "");
}

For GLM and DeepSeek groups the gateway turns on stream_options.include_usage, so the last chunk carries usage and has an empty choices list. Guard for that, as the examples do. An error after the stream has started arrives as an SSE error event.

#Tool calling

tools and tool_choice are forwarded to the model. Whether a model returns tool calls depends on the model, so test the one you plan to use. See Tool calling for the full loop.

Python
tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]

completion = client.chat.completions.create(
    model="glm-5.3",
    messages=[{"role": "user", "content": "What's the weather in Hangzhou?"}],
    tools=tools,
)
print(completion.choices[0].message.tool_calls)
Node.js
const tools = [{
  type: "function",
  function: {
    name: "get_weather",
    description: "Get the current weather for a city",
    parameters: {
      type: "object",
      properties: { city: { type: "string" } },
      required: ["city"],
    },
  },
}];

const completion = await client.chat.completions.create({
  model: "glm-5.3",
  messages: [{ role: "user", content: "What's the weather in Hangzhou?" }],
  tools,
});
console.log(completion.choices[0].message.tool_calls);

#Reasoning output

On GLM and DeepSeek groups the response body is passed through unchanged, so a thinking model's reasoning_content field reaches the SDK. It is not a typed attribute; read it as an extra field:

Python
message = completion.choices[0].message
print(getattr(message, "reasoning_content", None))
Node.js
console.log(completion.choices[0].message.reasoning_content);

See Reasoning & thinking for which parameters control thinking.

#Responses API

client.responses.create(...) calls https://bigmodel.io/v1/responses. Only some groups serve it; GLM and DeepSeek groups return 404 there. Chat Completions works for every text model. Over HTTP, previous_response_id is rejected with 400, so send the full input each time.

Python
response = client.responses.create(model="YOUR_MODEL_ID", input="ping")
print(response.output_text)
Node.js
const response = await client.responses.create({ model: "YOUR_MODEL_ID", input: "ping" });
console.log(response.output_text);

#Verify the setup

List the models your key can call. A list (possibly short) means the base URL and key are correct:

Python
for model in client.models.list():
    print(model.id)
Node.js
for await (const model of client.models.list()) {
  console.log(model.id);
}

Then send one request and confirm it appears in Usage.

#LangChain

LangChain's ChatOpenAI uses the same base URL:

python
import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="glm-5.3", base_url="https://bigmodel.io/v1", api_key=os.environ["BIGMODEL_API_KEY"])

Streaming usage, ChatAnthropic and the reasoning_content caveat are covered in LangChain.

#OpenRouter-style requests

The same endpoints accept provider/model names such as z-ai/glm-5.3, a models fallback array, and HTTP-Referer / X-Title headers. Pass extra body fields with extra_body (Python) or as plain properties (Node.js). See OpenRouter compatibility and Migrate from OpenRouter.

#Troubleshooting

404 on every request. The base URL is missing /v1 or already contains /chat/completions. Use exactly https://bigmodel.io/v1; the SDK adds the path.

401 INVALID_API_KEY or API_KEY_REQUIRED. The environment variable is empty in the process that runs your code. Print its first few characters, not the whole key.

503 No available accounts: no available accounts supporting model: .... The model ID is misspelled or your key's group does not serve it. IDs are lowercase with dots kept; copy one from client.models.list() or the model catalog.

404 ... only supports /v1/chat/completions. You called the Responses API with a key whose group only serves Chat Completions. Use chat.completions.create.

response_format seems ignored. On groups that are not GLM or DeepSeek, Chat Completions requests are converted, and response_format, n, seed, user and logprobs are dropped. See Structured output.

403 INSUFFICIENT_BALANCE. Your balance is at or below zero; top up in Billing. models.list() also needs a positive balance.

429 API_KEY_QUOTA_EXHAUSTED or rate_limit_exceeded. The key's quota or a 5h/1d/7d spend limit is used up, or you hit a request-per-minute limit. See Limits & rate limits. Keep the SDK's built-in retries for plain 429s.

Timeouts on long outputs. Use streaming, or raise the client timeout (timeout= in Python, timeout: in Node.js).

Updated · View as Markdown