OpenAI SDK
Use the OpenAI SDK to reach all 70+ text models on this gateway (Python / TypeScript / curl)
The broadest option — the OpenAI SDK can call every one of the gateway's 70+ text models (Claude, Gemini, GLM, Grok and the rest). Image, video and embedding models use separate endpoints, see Image / video / music APIs.
Endpoint#
| Value | |
|---|---|
| Base URL | https://jiuye.zsopc.com/v1 |
| Endpoint | /chat/completions (compatible with OpenAI Chat Completions) |
| Auth | Authorization: Bearer sk-gpushare-xxx (an x-api-key header also works — see Authentication) |
| Protocol | OpenAI Chat Completions (HTTP / SSE streaming) |
Getting a key, and how billing works#
- Create: make an API key in the jiuye.zsopc.com console (shown there as a "sub-key"), formatted
sk-gpushare-plus 64 hex characters. You can return to its detail page and view it again at any time. - Billing: charged per token against your account balance (a USD wallet) shared by every key; a key has no budget pool of its own. Sign-up includes $0.30 of trial credit, enough for every example on this page.
- Top up: dflop.top/dashboard/billing (Stripe, $1 minimum, same SSO account and shared balance as jiuye.zsopc.com).
- Usage: the console shows per-key calls and spend.
Install#
pip install openai # Python
npm install openai # TypeScript
Python#
Basic call#
from openai import OpenAI
client = OpenAI(
base_url="https://jiuye.zsopc.com/v1",
api_key="sk-gpushare-xxx",
)
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Say hello in one word."}],
)
print(resp.choices[0].message.content)
Streaming#
stream = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Stream a haiku about latency"}],
stream=True,
)
for chunk in stream:
if not chunk.choices: # the stream always ends with an empty-choices chunk carrying usage — skip it
continue
print(chunk.choices[0].delta.content or "", end="", flush=True)
The gateway force-injects
stream_options.include_usage, so every stream ends with achoices: []+usagechunk (that's the billing record). The Python example must checkchoicesfor emptiness, orchunk.choices[0]raisesIndexErroron that chunk (TypeScript's?.chaining is naturally safe).
Calling other vendors (the interesting part)#
The OpenAI SDK can call any model that supports the OpenAI Chat protocol — not just GPT:
# Claude
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Hello"}],
)
# Gemini
resp = client.chat.completions.create(
model="gemini-2.5-pro",
messages=[{"role": "user", "content": "Hello"}],
)
# GLM
resp = client.chat.completions.create(
model="glm-5.1",
messages=[{"role": "user", "content": "Hello"}],
)
Image generation (WebSocket streaming channel)#
The image_generation built-in tool is only supported by gpt-5.4 and gpt-5.5 (other models return 400 tool_not_supported), and it requires stream=True:
stream = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "Draw an orange cat in pixel art"}],
tools=[{"type": "image_generation"}],
stream=True,
)
# images arrive inline as markdown in delta.content:
# normal:  <- hosted URL, durable
# fallback:  <- used when the upload fails
for chunk in stream:
if not chunk.choices:
continue
print(chunk.choices[0].delta.content or "", end="", flush=True)
Handle both the URL and base64 forms. In multi-turn conversations, do not write the base64 form back into
messages[]verbatim — the whole image gets re-counted as text tokens and the cost explodes. For the standalone per-image endpoint/v1/images/generations(Seedream, Grok Imagine and others), see Image / video / music APIs.
Web search#
web_search covers most text models (models or channels that don't support it return 400 tool_not_supported; per-model support is in the compatibility matrix) and likewise requires stream=True:
stream = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": "What did Anthropic ship this week?"}],
tools=[{"type": "web_search"}],
stream=True,
)
for chunk in stream:
if not chunk.choices:
continue
print(chunk.choices[0].delta.content or "", end="", flush=True)
Function tools#
Compatible with OpenAI function-calling semantics — GPT, GLM and similar models pass straight through, while Claude and Gemini models go through the translation layer, which maps the standard tools, tool_choice, tool_calls and role: "tool" fields. This uses the HTTP channel, not WS V2, so stream: false works too:
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather in a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string"},
},
"required": ["city"],
},
},
}]
resp = client.chat.completions.create(
model="claude-sonnet-4-6",
messages=[{"role": "user", "content": "Weather in Tokyo?"}],
tools=tools,
)
print(resp.choices[0].message.tool_calls)
TypeScript#
Basic call#
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.PLATFORM_API_KEY,
baseURL: "https://jiuye.zsopc.com/v1",
});
const resp = await client.chat.completions.create({
model: "gpt-5.4",
messages: [{ role: "user", content: "Say hello in one word." }],
});
console.log(resp.choices[0].message.content);
Streaming#
const stream = await client.chat.completions.create({
model: "claude-sonnet-4-6",
messages: [{ role: "user", content: "Stream a haiku" }],
stream: true,
});
for await (const chunk of stream) {
// the trailing usage chunk has empty choices; ?. chaining skips it safely
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}
Calling other vendors#
// Claude
await client.chat.completions.create({
model: "claude-opus-4-6",
messages: [{ role: "user", content: "Hello" }],
});
// Grok
await client.chat.completions.create({
model: "grok-4-fast-reasoning",
messages: [{ role: "user", content: "Hello" }],
});
curl#
Non-streaming#
curl https://jiuye.zsopc.com/v1/chat/completions \
-H "Authorization: Bearer $PLATFORM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.4",
"messages": [
{"role": "user", "content": "Say hello in one word."}
]
}'
Streaming#
curl https://jiuye.zsopc.com/v1/chat/completions \
-H "Authorization: Bearer $PLATFORM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"stream": true,
"messages": [
{"role": "user", "content": "Stream a haiku"}
]
}' \
--no-buffer
Things to know#
stream: falseonly supports plain text plus function tools.web_searchandimage_generationrequirestream: true- The trailing usage chunk: the gateway force-injects
stream_options.include_usage, so every stream ends with achoices: []+usagechunk (the billing record). Check for emptiness before indexingchoices[0] - Built-in tool coverage:
image_generationisgpt-5.4/gpt-5.5only;web_searchcovers most but not all text models. Unsupported combinations return 400tool_not_supported— per-model support is in the compatibility matrix - Model scope:
/chat/completionsserves text (chat) models only. Image, video and embedding SKUs have their own endpoints (see Image / video / music APIs) and return 503no_channel_availableif called here. A nonexistent model id returns 400model_not_found(not 404). If the key was created with anallowed_modelsallowlist, calling outside it returns 400model_not_allowed - Errors always come back OpenAI-style:
{"error": {"message": "...", "type": "...", "code": "..."}}— full table in the error reference - Out of balance returns HTTP 402 with code
quota_exceeded(typeinsufficient_quota). The balance is account-level and shared by all keys, so a new key won't help — top up at dflop.top/dashboard/billing - Timeouts: the upstream ceiling is 180 seconds per request, after which you get 504
upstream_timeout(streaming is bound by the same total). Set the SDKtimeoutto ≥ 200s, and usestream: truefor long outputs so you can process as it arrives
Full model list#
See Models or the compatibility matrix. You can also call client.models.list() from the SDK (that's GET /v1/models, which only accepts Authorization: Bearer or x-api-key header auth).