The hosted gateway is OpenAI-compatible, so the official openai SDK works against it unmodified. If you already have code written against OpenAI or another OpenAI-compatible provider, this is the whole migration:

python
# Change these two arguments — everything else about your OpenAI SDK code stays the same.client = OpenAI( base_url="https://b3iq.org/v1/api", api_key="b3iq_gateway_...")

Everything downstream — chat.completions.create, streaming, models.list(), error handling — is standard SDK code. Requests are free and route only to the machines on your own account.

Coming from OpenRouter or OpenAI directly?

Same two-line swap. Change base_url/baseURL and api_key/apiKey only — model ids, message shape, and streaming stay standard OpenAI SDK.

Before You Start

1

Create a gateway key

Sign in to the dashboard and create a gateway key. Hosted keys are b3iq_gateway_ secrets — shown once, stored hashed, and revocable.

2

Have a machine online

Your key routes only to machines on your own account, so you need at least one online machine serving the model you want to call. See Run your first node.

3

Install the SDK

bash
pip install openai
Keep the key out of source

Read b3iq_gateway_ secrets from an environment variable, not a literal string in committed code.

bash
export B3IQ_GATEWAY_API_KEY="b3iq_gateway_..."

Create The Client

python
import osfrom openai import OpenAIclient = OpenAI( base_url="https://b3iq.org/v1/api", api_key=os.environ["B3IQ_GATEWAY_API_KEY"],)

List Your Models

Call models.list() before you call chat — it tells you exactly what you can route to right now.

python
for model in client.models.list(): print(model.id)
Your models, not the network's

Called with your gateway key, models.list() returns only the models the machines on your account serve right now — any node scope on the key is respected, and machines you've switched to Earn mode are excluded. Any id the call returns is an id you can dispatch to; the set changes as your machines come and go, so list before you call rather than hardcoding an id. Without a key, the same endpoint returns the public network-wide catalog instead — see Hosted Gateway.

Chat Completion

python
response = client.chat.completions.create( model="qwen3-8b", # use an id from models.list() messages=[{"role": "user", "content": "Say hello from B3IQ."}],)print(response.choices[0].message.content)

A successful call returns a standard OpenAI ChatCompletion object, served free by a machine on your account.

Streaming

Set stream=True / stream: true and iterate the SDK's stream object exactly as you would against OpenAI.

python
stream = client.chat.completions.create( model="qwen3-8b", messages=[{"role": "user", "content": "Stream a short response."}], stream=True,)for chunk in stream: delta = chunk.choices[0].delta.content if delta: print(delta, end="", flush=True)

Streamed requests are metered the same as non-streamed ones — get the non-streaming call working first, then flip stream on.

Handling Errors

Denials come back as a standard OpenAI-style error object, so SDK exceptions behave the way they do against OpenAI — catch the SDK's API error type and branch on the stable machine code, not the human-readable message.

python
from openai import APIStatusErrortry: client.chat.completions.create( model="qwen3-8b", messages=[{"role": "user", "content": "Say hello from B3IQ."}], )except APIStatusError as e: print(e.status_code, e.code)

A no_eligible_nodes code means no machine on your account serves that model right now — call models.list() again rather than retrying blind. See Errors for the full list of stable codes.

Or check with the CLI

The b3iq CLI makes the same calls without writing code: install it, run b3iq login, then b3iq models list to see what your keys can route to.

Call the gateway

The same flow over raw HTTP with curl and fetch, plus the full error and streaming walkthrough.

Learn More
Hosted gateway

Full endpoint list, headers, and the gate order a request passes.

Learn More
Usage & quotas

Free inference, per-key metering, rate limits, and the token quota.

Learn More
Ask a question... ⌘I