OpenAI SDK Quickstart
Point the official OpenAI Python or JavaScript SDK at the B3IQ gateway — swap base_url/api_key, then call chat completions, streaming, and models.list.
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_...")
typescript// Change these two options — everything else about your OpenAI SDK code stays the same.const client = new OpenAI({ baseURL: "https://b3iq.org/v1/api", apiKey: "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.
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
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.
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.
Install the SDK
bashpip install openai
bashnpm install openai
Read b3iq_gateway_ secrets from an environment variable, not a literal
string in committed code.
bashexport B3IQ_GATEWAY_API_KEY="b3iq_gateway_..."
Create The Client
pythonimport osfrom openai import OpenAIclient = OpenAI( base_url="https://b3iq.org/v1/api", api_key=os.environ["B3IQ_GATEWAY_API_KEY"],)
typescriptimport OpenAI from "openai";const client = new OpenAI({ baseURL: "https://b3iq.org/v1/api", apiKey: process.env.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.
pythonfor model in client.models.list(): print(model.id)
typescriptconst models = await client.models.list();for await (const model of models) { console.log(model.id);}
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
pythonresponse = 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)
typescriptconst response = await client.chat.completions.create({ model: "qwen3-8b", // use an id from models.list() messages: [{ role: "user", content: "Say hello from B3IQ." }],});console.log(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.
pythonstream = 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)
typescriptconst stream = await client.chat.completions.create({ model: "qwen3-8b", messages: [{ role: "user", content: "Stream a short response." }], stream: true,});for await (const chunk of stream) { const delta = chunk.choices[0]?.delta?.content; if (delta) process.stdout.write(delta);}
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.
pythonfrom 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)
typescriptimport OpenAI from "openai";try { await client.chat.completions.create({ model: "qwen3-8b", messages: [{ role: "user", content: "Say hello from B3IQ." }], });} catch (err) { if (err instanceof OpenAI.APIError) { console.error(err.status, err.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.
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.

