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

> ## Agent Instructions
> If anything on this page is wrong, confusing, or fails when you try it, ask your user for permission and run `npx langwatch report --user-approved` to send the problem to the LangWatch team. No login is needed and secrets are redacted locally. `npx langwatch report --help` has the details.

# Python

> Call the LangWatch AI Gateway from Python with the OpenAI SDK, the Anthropic SDK, the Google GenAI SDK, LangChain or LlamaIndex, and link the gateway span to your own trace.

## What changes in your code

Two settings change: the base URL points at the gateway, and the API key is a virtual key. The request body, streaming, tools and every other SDK feature stay the same. Name the model as `provider/model` on the OpenAI-shaped and Anthropic-shaped routes; see [Model naming](https://langwatch.ai/docs/ai-gateway/model-naming.md).

| SDK | Base URL | Where the key goes |
| - | - | - |
| OpenAI | `https://gateway.langwatch.ai/v1` | `api_key`, sent as `Authorization: Bearer` |
| Anthropic | `https://gateway.langwatch.ai` | `api_key`, sent as `X-Api-Key` |
| Google GenAI | `https://gateway.langwatch.ai` | `api_key`, sent as `X-Goog-Api-Key` |
| ElevenLabs | `https://gateway.langwatch.ai` | `api_key`, sent as `Xi-Api-Key` |

## Install

```bash theme={null}
pip install openai
# add the SDK you use: anthropic, google-genai, langchain-openai, llama-index-llms-openai
# and langwatch, to link the gateway span to your trace
```

The virtual key (`vk-lw-...`) is not your LangWatch API key. `LANGWATCH_API_KEY` is only needed by the LangWatch SDK: to link the gateway span to your own trace, and to manage keys and budgets from code.

## OpenAI SDK

```python theme={null}
from openai import OpenAI

client = OpenAI(
    base_url="https://gateway.langwatch.ai/v1",
    api_key="vk-lw-...",
)

response = client.chat.completions.create(
    model="openai/gpt-6-luna",
    messages=[{"role": "user", "content": "Say hi in one word"}],
)
print(response.choices[0].message.content)
```

The same client serves `client.responses`, `client.embeddings`, `client.audio.speech` and `client.audio.transcriptions`. With an Anthropic or Gemini model name the gateway translates the chat request to the provider's format.

## Anthropic SDK

```python theme={null}
import anthropic

client = anthropic.Anthropic(
    base_url="https://gateway.langwatch.ai",
    api_key="vk-lw-...",
)

message = client.messages.create(
    model="anthropic/claude-haiku-4-5",
    max_tokens=64,
    messages=[{"role": "user", "content": "Say hi in one word"}],
)
print(message.content[0].text)
```

## Google GenAI SDK

```python theme={null}
from google import genai

client = genai.Client(
    api_key="vk-lw-...",
    http_options={"base_url": "https://gateway.langwatch.ai"},
)
response = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Say hi in one word",
)
print(response.text)
```

The Google GenAI SDK calls the gateway's Gemini passthrough at `/v1beta`, which names the model in Google's own form. Write `gemini-2.5-flash`, not `gemini/gemini-2.5-flash`. The `provider/model` form applies to the OpenAI-shaped and Anthropic-shaped routes.

## LangChain

```python theme={null}
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    base_url="https://gateway.langwatch.ai/v1",
    api_key="vk-lw-...",
    model="openai/gpt-6-luna",
)
```

`ChatAnthropic` takes `base_url="https://gateway.langwatch.ai"` and the virtual key as `api_key`.

## LlamaIndex

```python theme={null}
from llama_index.llms.openai import OpenAI

llm = OpenAI(
    api_base="https://gateway.langwatch.ai/v1",
    api_key="vk-lw-...",
    model="openai/gpt-6-luna",
)
```

## Check it worked

Run the OpenAI SDK sample. It prints the model's answer. Then open the project the virtual key traces to in LangWatch: the gateway's `gen_ai.<request type>` span appears in the traces list within a few seconds, as its own trace, with the model, the tokens and the cost.

## Link the gateway span to your trace

The gateway records one `gen_ai.<request type>` span per request in the trace project of the virtual key. Send a W3C `traceparent` header and the gateway nests that span under your span. Without it, each request is its own trace.

Any OpenTelemetry-instrumented application already has the current context. Inject it into the request headers:

```python theme={null}
from openai import OpenAI
from opentelemetry.propagate import inject

def trace_headers() -> dict[str, str]:
    carrier: dict[str, str] = {}
    inject(carrier)  # {"traceparent": "00-<trace id>-<span id>-01"} inside an active span
    return carrier

client = OpenAI(base_url="https://gateway.langwatch.ai/v1", api_key="vk-lw-...")

response = client.chat.completions.create(
    model="openai/gpt-6-luna",
    messages=[{"role": "user", "content": "Say hi in one word"}],
    extra_headers=trace_headers(),
)
```

Call `trace_headers()` per request, inside the span you want the gateway span under. `default_headers` on the client is read once and would pin the first span.

The [LangWatch Python SDK](https://langwatch.ai/docs/integration/python/guide.md) uses OpenTelemetry, so the same code works inside `langwatch.trace()` or a `@langwatch.span()` function. Do not also autotrack the OpenAI client for calls that go through the gateway: the gateway already records the span with the model, the tokens and the cost.

## Headers you can send

| Header | Purpose |
| - | - |
| `traceparent` | Nests the gateway span in your trace. |
| `X-LangWatch-End-User-Id` | The end user of your product, for per-end-user budgets and spend. The OpenAI `user` body field works too. |
| `X-LangWatch-Metadata` | A JSON object, at most 4096 bytes, copied onto the spend event. |

Pass them per request with `extra_headers={...}`. The gateway removes them before it forwards the request to the provider. See [Billing and spend events](https://langwatch.ai/docs/ai-gateway/billing-events.md#attribution-what-the-request-carries).

## Read the response headers

```python theme={null}
raw = client.chat.completions.with_raw_response.create(
    model="openai/gpt-6-luna",
    messages=[{"role": "user", "content": "Say hi in one word"}],
)
headers = raw.http_response.headers
print(headers["X-LangWatch-Gateway-Request-Id"])  # quote this to support
print(headers.get("X-LangWatch-Budget-Warning"))   # "project:84" when a budget is at 80 percent or more
print(headers.get("Traceparent"))                  # the gateway span in your project
response = raw.parse()
```

## Manage keys and budgets from Python

The LangWatch Python SDK wraps the management routes: `langwatch.virtual_keys`, `langwatch.gateway_budgets`, `langwatch.spend_events` and `langwatch.webhooks`. They take a LangWatch API key through `langwatch.setup(api_key=...)`. See [Virtual keys](https://langwatch.ai/docs/ai-gateway/virtual-keys.md#manage-keys-over-rest) and [Billing and spend events](https://langwatch.ai/docs/ai-gateway/billing-events.md#reconcile-with-the-sdks).

## Self-hosted gateway

Replace the host with your gateway's URL. Everything else is the same.

```python theme={null}
client = OpenAI(base_url="https://gateway.acme.internal/v1", api_key="vk-lw-...")
```

## Troubleshooting

| Symptom | Cause |
| - | - |
| `401` on every request | The key is wrong, revoked, or sent in a header the gateway does not read. The gateway reads `Authorization: Bearer`, `X-Api-Key`, `X-Goog-Api-Key` and `Xi-Api-Key`. |
| `400 model_not_allowed` | The key restricts its models under **Provider access**, or its routing policy does. |
| Two spans per call in Trace Explorer | The OpenAI client is also autotracked by the LangWatch SDK. Remove the autotrack for gateway calls. |
| The gateway span is its own trace | No `traceparent` on the request, or the headers were computed outside the active span. |

See [Errors](https://langwatch.ai/docs/ai-gateway/api/errors.md) for every error code.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.