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

# OpenAI

> Route and trace the OpenAI SDK through Orbitrage.

`init()` points the OpenAI client at the gateway for you — use the SDK exactly as
you do today.

<CodeGroup>
  ```python Python theme={null}
  import os, orbitrage
  orbitrage.init(os.environ["ORBITRAGE_API_KEY"], user_id="customer_42")

  from openai import OpenAI
  client = OpenAI()                       # base_url + auth handled by Orbitrage
  client.chat.completions.create(
      model="minimax-m3",                       # or pin: "gpt-5.4", "glm-5.2"
      messages=[{"role": "user", "content": "hi"}],
  )
  ```

  ```typescript Node.js theme={null}
  import { orbitrage } from "orbitrage";
  await orbitrage.init({ apiKey: process.env.ORBITRAGE_API_KEY, userId: "customer_42" });

  import OpenAI from "openai";
  await new OpenAI().chat.completions.create({
    model: "minimax-m3",
    messages: [{ role: "user", content: "hi" }],
  });
  ```
</CodeGroup>

## How a bare `OpenAI()` reaches Orbitrage

You don't pass a `base_url` — `init()` does it for you. On `init()` the SDK
patches the `OpenAI` / `AsyncOpenAI` constructor so that, **when you don't supply
your own `base_url`**, every client you build:

1. gets `base_url = https://api.orbitrage.ai/v1`, and
2. is authenticated with your **`orb_` key** — even if `OPENAI_API_KEY` is set in
   your environment. (The gateway only accepts `orb_` keys; your provider keys
   never leave your machine.)

So a plain `OpenAI()` always comes to Orbitrage with the right key:

```python theme={null}
import orbitrage; orbitrage.init("orb_...")           # OPENAI_API_KEY can be set — it's ignored for routing
from openai import OpenAI
c = OpenAI()
assert str(c.base_url).startswith("https://api.orbitrage.ai")   # ✅ routed to us
assert str(c.api_key).startswith("orb_")                        # ✅ orb key used, not sk-...
```

If you pass your own `base_url`, Orbitrage never overrides it — you stay in
control.

## Managed tools

Reference a [managed tool](/concepts/tools-gateway) by name and Orbitrage runs it
server-side — no keys, no tool loop:

```python theme={null}
resp = client.chat.completions.create(
    model="minimax-m3",
    messages=[{"role": "user", "content": "Compute 1234*5678. Only the number."}],
    tools=["calculator_orbitrage"],
)
print(resp.choices[0].message.content)   # 7006652
```

* `model: "auto"` routes to the cheapest capable model. Any model id pins it.
* Streaming, tools, and vision all work unchanged — see [Tool calling](/examples/tool-calling) and [Streaming](/examples/streaming).
