Skip to content

OpenAI SDK

Call HopBase with the OpenAI Python or Node.js SDK.

Existing OpenAI SDK applications only need a different Base URL, plan key, and model ID. Keep the application's current framework and error handling.

ItemValue
Base URLhttps://api.hop-base.com/v1
Key environment variableHOPBASE_OPENAI_API_KEY
ModelsGPT, Gemini, GLM chat, and other OpenAI-compatible models
Model IDUse an ID returned by GET /v1/models for the selected key

Install and send a minimal request

Install the SDK:

python -m pip install openai

Send a request:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.hop-base.com/v1",
    api_key=os.environ["HOPBASE_OPENAI_API_KEY"],
)

resp = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "Hello"}],
)
print(resp.choices[0].message.content)

Start with the prompt “Reply only with ok.” Add stream: true only when the application actually uses streaming, then verify that SSE events arrive incrementally.

Chat and image generation are in different groups.
  • GPT chat and Responses: the Codex Plus, Codex Pro, or GPT Official Direct (Azure) group. Gemini, GLM, and other chat models are in their own groups.
  • Image generation (gpt-image-*): the GPT Image (all models) group has every model; the GPT Official Direct (Azure) group also has gpt-image-2.5-flare and gpt-image-2.5-sunburst. A key with no group that offers the requested image model gets 404. See the Image API.
  • If one application uses both, add both groups to one key, or keep two keys in separate environment variables (for example, add HOPBASE_IMAGE_API_KEY) as the examples above do.

Never put a real key in source code. Inject HOPBASE_OPENAI_API_KEY through your deployment platform, a local .env file, or the system environment. Never commit .env or a real key to Git.

Supported request parameters

This table lists only the fields the gateway checks, rewrites, or rejects on POST /v1/chat/completions and POST /v1/responses. Other OpenAI fields are forwarded unchanged and follow the model's official limits. Context and output limits per model are in the model list; Gemini group differences are in Gemini chat.

ParameterRequiredType & limitsDefaultDescription
modelRequiredstring, a model ID in the current key's group—A model outside the group returns 404 model_not_found; image models such as gpt-image-* return 400 image models do not support Chat Completions, please use the Images API on chat endpoints
messagesRequired for Chat Completionsarray, at least 1 item—Missing returns 400 missing messages field; an empty array returns 400 messages must not be an empty array
inputRequired for Responsesstring or array—A string is wrapped into a single user message
max_tokens / max_completion_tokens / max_output_tokensOptionalinteger; the gateway does not clamp or rewrite itModel defaultThe ceiling is the model's official limit; the model returns an error above it
streamOptionalbooleanfalsetrue returns SSE
stream_options.include_usageOptionalbooleanfalseWhen streaming, send true to receive the final usage-only event; without it that event is not sent (billing is unaffected)
tools / tool_choiceOptionalOpenAI function tools format—Forwarded unchanged
service_tierOptionalonly priority / flex are kept; fast is treated as priority—Other values are removed before forwarding, without an error. Fast (priority) only takes effect, and is only billed at the Fast rate, when your group supports it; otherwise the request runs and is billed at the standard tier
previous_response_id—Not supported (Responses)—The gateway removes this field, so the previous turn is not continued; send the full history in input for multi-turn conversations
store—Always false (Responses)falseResponses are not stored server-side and cannot be retrieved by ID later

The whole request body is capped at 60 MB; larger bodies return 413.

GPT Official Direct (Azure) group differences.
  • Model names match OpenAI's. Chat: gpt-6-sol, gpt-6-luna, gpt-6-astra, gpt-6.1-sol, gpt-5.6-sol, gpt-5.6-terra, gpt-5.6-luna, gpt-5.5, gpt-5.4. Images: gpt-image-2.5-flare and gpt-image-2.5-sunburst (/v1/images/generations and /v1/images/edits, returned synchronously as Base64). No codex-* or gpt-image-2.
  • service_tier: "priority" (including fast) is not supported: requests run on the standard tier and are billed at the standard price.
  • The model field in responses may be a dated snapshot name (for example, gpt-5.5-2026-04-24), matching the official OpenAI API. Billing uses the model ID you requested; the console Usage logs may also show the snapshot name. Do not assert response.model == request.model.

Stream output and get usage

After passing stream_options.include_usage, the last event has empty choices and its usage field carries the token usage for the request.

stream = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "Describe yourself in three sentences"}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)
    if chunk.usage:  # Last event: choices is empty, only usage is set
        print()
        print(chunk.usage)

Read the charge for a request

A billed non-streaming request returns the USD amount actually deducted from your balance in the X-HopBase-Cost-USD response header, the same charge in CNY in X-HopBase-Cost, and the currency of X-HopBase-Cost (always CNY) in X-HopBase-Currency. The JSON response also carries the same cost, cost_usd, and currency in usage, and the SDK keeps them as extra fields. Streaming responses carry none of these; check the charge under Usage in the console. See Charges for the full rules.

raw = client.chat.completions.with_raw_response.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "Reply only with ok"}],
)
print(raw.headers.get("x-hopbase-cost"), raw.headers.get("x-hopbase-cost-usd"), raw.headers.get("x-hopbase-currency"))
resp = raw.parse()  # Same return value as without with_raw_response
print(resp.usage.cost, resp.usage.cost_usd, resp.usage.currency)  # Extra fields, same values as the headers

Tool calls

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Look up the weather for a city",
        "parameters": {
            "type": "object",
            "properties": {"city": {"type": "string"}},
            "required": ["city"],
        },
    },
}]
messages = [{"role": "user", "content": "What's the weather like in Shanghai today?"}]

resp = client.chat.completions.create(model="gpt-5.6-sol", messages=messages, tools=tools)
msg = resp.choices[0].message
if msg.tool_calls:
    call = msg.tool_calls[0]
    print(call.function.name, call.function.arguments)
    # Run the tool, then feed the result back; tool_call_id must match the previous call.id
    messages += [msg, {"role": "tool", "tool_call_id": call.id, "content": "Sunny, 26°C"}]
    resp = client.chat.completions.create(model="gpt-5.6-sol", messages=messages, tools=tools)
print(resp.choices[0].message.content)

Timeouts and retries

openai-python and openai-node default to a 600-second read timeout and 2 automatic retries. Use streaming for long outputs; see Concurrency, timeouts, and billing for concurrency limits and timeouts.

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.hop-base.com/v1",
    api_key=os.environ["HOPBASE_OPENAI_API_KEY"],
    timeout=600,    # seconds; prefer streaming for long outputs
    max_retries=2,  # automatic retries for connection errors, 429, and 5xx
)

Next steps