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.
| Item | Value |
|---|---|
| Base URL | https://api.hop-base.com/v1 |
| Key environment variable | HOPBASE_OPENAI_API_KEY |
| Models | GPT, Gemini, GLM chat, and other OpenAI-compatible models |
| Model ID | Use an ID returned by GET /v1/models for the selected key |
Install and send a minimal request
Install the SDK:
python -m pip install openaiSend 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.
- 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 hasgpt-image-2.5-flareandgpt-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.
| Parameter | Required | Type & limits | Default | Description |
|---|---|---|---|---|
model | Required | string, 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 |
messages | Required for Chat Completions | array, at least 1 item | — | Missing returns 400 missing messages field; an empty array returns 400 messages must not be an empty array |
input | Required for Responses | string or array | — | A string is wrapped into a single user message |
max_tokens / max_completion_tokens / max_output_tokens | Optional | integer; the gateway does not clamp or rewrite it | Model default | The ceiling is the model's official limit; the model returns an error above it |
stream | Optional | boolean | false | true returns SSE |
stream_options.include_usage | Optional | boolean | false | When streaming, send true to receive the final usage-only event; without it that event is not sent (billing is unaffected) |
tools / tool_choice | Optional | OpenAI function tools format | — | Forwarded unchanged |
service_tier | Optional | only 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) | false | Responses 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.
- 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-flareandgpt-image-2.5-sunburst(/v1/images/generationsand/v1/images/edits, returned synchronously as Base64). Nocodex-*orgpt-image-2. service_tier: "priority"(includingfast) is not supported: requests run on the standard tier and are billed at the standard price.- The
modelfield 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 assertresponse.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 headersTool 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
- For image generation, see the Image API
- For Gemini chat, see Gemini chat
- For Claude models, use the Anthropic SDK
- When something fails, check Troubleshooting