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 URLhttps://jiuye.zsopc.com/v1
Endpoint/chat/completions (compatible with OpenAI Chat Completions)
AuthAuthorization: Bearer sk-gpushare-xxx (an x-api-key header also works — see Authentication)
ProtocolOpenAI 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 a choices: [] + usage chunk (that's the billing record). The Python example must check choices for emptiness, or chunk.choices[0] raises IndexError on 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:   ![](https://r2.dflop.top/...)    <- hosted URL, durable
#   fallback: ![](data:image/png;base64,...)   <- 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 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: false only supports plain text plus function tools. web_search and image_generation require stream: true
  • The trailing usage chunk: the gateway force-injects stream_options.include_usage, so every stream ends with a choices: [] + usage chunk (the billing record). Check for emptiness before indexing choices[0]
  • Built-in tool coverage: image_generation is gpt-5.4 / gpt-5.5 only; web_search covers most but not all text models. Unsupported combinations return 400 tool_not_supported — per-model support is in the compatibility matrix
  • Model scope: /chat/completions serves text (chat) models only. Image, video and embedding SKUs have their own endpoints (see Image / video / music APIs) and return 503 no_channel_available if called here. A nonexistent model id returns 400 model_not_found (not 404). If the key was created with an allowed_models allowlist, calling outside it returns 400 model_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 (type insufficient_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 SDK timeout to ≥ 200s, and use stream: true for 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).