# OpenAI SDK

> Use the OpenAI SDK to reach all 103 text models on this gateway (Python / TypeScript / curl)

来源：https://zhonkemodel.dflop.top/en/docs/sdks/openai-sdk

> The broadest option — the OpenAI SDK can call every one of the gateway's 103 text models (Claude, Gemini, GLM, Grok and the rest). Image, video and embedding models use separate endpoints, see [Image / video / music APIs](../reference/media-apis.md).

## Endpoint

| | Value |
|---|---|
| Base URL | `https://zhonkezhonkeapi.dflop.top/v1` |
| Endpoint | `/chat/completions` (compatible with OpenAI Chat Completions) |
| Auth | `Authorization: Bearer sk-gpushare-xxx` (an `x-api-key` header also works — see [Authentication](../reference/authentication.md)) |
| Protocol | OpenAI Chat Completions (HTTP / SSE streaming) |

## Getting a key, and how billing works

- **Create**: make an API key in the zhonkemodel.dflop.top 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 zhonkemodel.dflop.top).
- **Usage**: the console shows per-key calls and spend.

## Install

```bash
pip install openai          # Python
npm install openai          # TypeScript
```

## Python

### Basic call

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://zhonkezhonkeapi.dflop.top/v1",
    api_key="sk-gpushare-xxx",
)

resp = client.chat.completions.create(
    model="gpt-5.5",
    messages=[{"role": "user", "content": "Say hello in one word."}],
)
print(resp.choices[0].message.content)
```

### Streaming

```python
stream = client.chat.completions.create(
    model="gpt-5.5",
    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:

```python
# 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.5`** (other models return 400 `tool_not_supported`), and it requires `stream=True`:

```python
stream = client.chat.completions.create(
    model="gpt-5.5",
    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](../reference/media-apis.md).

### 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](../reference/compatibility-matrix.md)) and likewise requires `stream=True`:

```python
stream = client.chat.completions.create(
    model="gpt-5.5",
    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:

```python
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

```typescript
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.PLATFORM_API_KEY,
  baseURL: "https://zhonkezhonkeapi.dflop.top/v1",
});

const resp = await client.chat.completions.create({
  model: "gpt-5.5",
  messages: [{ role: "user", content: "Say hello in one word." }],
});

console.log(resp.choices[0].message.content);
```

### Streaming

```typescript
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

```typescript
// 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

```bash
curl https://zhonkezhonkeapi.dflop.top/v1/chat/completions \
  -H "Authorization: Bearer $PLATFORM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.5",
    "messages": [
      {"role": "user", "content": "Say hello in one word."}
    ]
  }'
```

### Streaming

```bash
curl https://zhonkezhonkeapi.dflop.top/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.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](../reference/compatibility-matrix.md)
- **Model scope**: `/chat/completions` serves text (chat) models only. Image, video and embedding SKUs have their own endpoints (see [Image / video / music APIs](../reference/media-apis.md)) 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](../reference/errors.md)
- **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](../reference/models.md) or the [compatibility matrix](../reference/compatibility-matrix.md). 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).
