> ## Documentation Index
> Fetch the complete documentation index at: https://docs.b3iq.org/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI SDK Quickstart

Use the OpenAI Python or JavaScript SDK with B3IQ: configure your key and endpoint, select a served model, and send chat or streaming requests.

The hosted gateway is OpenAI-compatible, so the official `openai` SDK works
for the supported chat, streaming, and model-list methods. Start by changing
the base URL and key, then select a model your own machine is serving.

Set `B3IQ_API_KEY` to your gateway key as described below. These examples use
`your-served-model-id`; replace it with a model ID returned by `client.models.list()`.
The model must be served by your machines and available to this key. Changing
the client configuration does not change an existing request's `model` value.

```python app.py
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://b3iq.org/v1/api",
    api_key=os.environ["B3IQ_API_KEY"],
)

reply = client.chat.completions.create(
    model="your-served-model-id",
    messages=[{"role": "user", "content": "Hi"}],
)
print(reply.choices[0].message.content)
```

```typescript app.ts
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://b3iq.org/v1/api",
  apiKey: process.env.B3IQ_API_KEY,
});

const reply = await client.chat.completions.create({
  model: "your-served-model-id",
  messages: [{ role: "user", content: "Hi" }],
});
console.log(reply.choices[0].message.content);
```

`chat.completions.create`, streaming, and `models.list()` use the SDK methods
shown below. Provider-specific tools and unsupported endpoints do not become
available by changing the base URL. Requests are **free** and route only to
the machines on **your own account**.

**Coming from OpenRouter or OpenAI directly?**

Change `base_url`/`baseURL` and `api_key`/`apiKey`, then set `model` on each
  request to an ID available to your B3IQ key. Model IDs and optional features
  can differ between providers.

## 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](/guides/run-your-first-node).
  **Install the SDK**

```bash Python
    pip install openai
    ```
    ```bash JavaScript
    npm 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_API_KEY="b3iq_gateway_..."
```

## Create the client

```python client.py
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://b3iq.org/v1/api",
    api_key=os.environ["B3IQ_API_KEY"],
)
```

```typescript client.ts
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://b3iq.org/v1/api",
  apiKey: process.env.B3IQ_API_KEY,
});
```

## List your models

Call `models.list()` before you call chat. It tells you exactly what you can
route to right now. Replace `your-served-model-id` in the examples with the exact
ID returned by the list, including any model tag. The placeholder is not a model
you can call.

```python list_models.py
for model in client.models.list():
    print(model.id)
```

```typescript list-models.ts
const models = await client.models.list();
for await (const model of models) {
  console.log(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. The list reflects
  eligible routes at request time; the set changes as your
  machines come and go, so list before you call rather than hardcoding an id.
  Without an owner-scoped key, the same endpoint returns `data: []`. It does
  not advertise a shared public pool. See [Hosted Gateway](/developers/hosted-gateway).

If the list is empty or your expected model is missing, check that the key belongs
to the intended account, its machine scope includes the serving machine, and that
machine is online, serving the model, and not in Earn mode. Check the machine's
model status in the dashboard, then list models again.

## Chat completion

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

```typescript chat.ts
const response = await client.chat.completions.create({
  model: "your-served-model-id", // 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.

```python stream.py
stream = client.chat.completions.create(
    model="your-served-model-id",
    messages=[{"role": "user", "content": "Stream a short response."}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content if chunk.choices else None
    if delta:
        print(delta, end="", flush=True)
```

```typescript stream.ts
const stream = await client.chat.completions.create({
  model: "your-served-model-id",
  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.

```python errors.py
from openai import APIStatusError

try:
    client.chat.completions.create(
        model="your-served-model-id",
        messages=[{"role": "user", "content": "Say hello from B3IQ."}],
    )
except APIStatusError as e:
    print(e.status_code, e.code)
```

```typescript errors.ts
import OpenAI from "openai";

try {
  await client.chat.completions.create({
    model: "your-served-model-id",
    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](/developers/errors) for the full list of stable codes.

**Or check with the CLI**

The [b3iq CLI](/developers/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.

## Related

**[Call the gateway](/guides/call-the-gateway)**

The same flow over raw HTTP with curl and fetch, plus the full error and
    streaming walkthrough.
  **[Hosted gateway](/developers/hosted-gateway)**

Full endpoint list, headers, and the gate order a request passes.
  **[Usage & quotas](/developers/usage-and-quotas)**

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