> ## 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.

# Any OpenAI-compatible client

> Call the LangWatch AI Gateway with curl or any client that lets you set an OpenAI base URL and API key, and link the gateway span to your own trace.

## What changes in your client

Any client that lets you set an OpenAI base URL and an API key works with the gateway. Set the base URL to `https://gateway.langwatch.ai/v1` and send the virtual key as `Authorization: Bearer`. The request body, streaming and tools stay the same. Name the model as `provider/model`; see [Model naming](https://langwatch.ai/docs/ai-gateway/model-naming.md).

| Route | Shape | Where the key goes |
| - | - | - |
| `POST /v1/chat/completions` | OpenAI | `Authorization: Bearer vk-lw-...` |
| `POST /v1/messages` | Anthropic | `X-Api-Key: vk-lw-...` |

The virtual key (`vk-lw-...`) is not your LangWatch API key. For the SDKs, see the [TypeScript SDK](https://langwatch.ai/docs/ai-gateway/sdks/typescript.md), the [Python SDK](https://langwatch.ai/docs/ai-gateway/sdks/python.md) and the [Go SDK](https://langwatch.ai/docs/ai-gateway/sdks/go.md).

## Chat completions

```bash theme={null}
curl https://gateway.langwatch.ai/v1/chat/completions \
  -H "Authorization: Bearer $LANGWATCH_VIRTUAL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5-mini",
    "messages": [{"role": "user", "content": "Say hi in one word"}]
  }'
```

Add `"stream": true` to stream the answer as server-sent events. Use `curl -N` so curl does not buffer the frames:

```bash theme={null}
curl -N https://gateway.langwatch.ai/v1/chat/completions \
  -H "Authorization: Bearer $LANGWATCH_VIRTUAL_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5-mini",
    "messages": [{"role": "user", "content": "Count to 5"}],
    "stream": true
  }'
```

The response is `text/event-stream`, one `data:` frame per chunk, ending with `data: [DONE]`. See [Streaming](https://langwatch.ai/docs/ai-gateway/streaming.md).

## Messages (Anthropic shape)

```bash theme={null}
curl https://gateway.langwatch.ai/v1/messages \
  -H "X-Api-Key: $LANGWATCH_VIRTUAL_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-haiku-4-5",
    "max_tokens": 64,
    "messages": [{"role": "user", "content": "Say hi in one word"}]
  }'
```

`Authorization: Bearer` works in place of `X-Api-Key`. The gateway reads `Authorization: Bearer`, `X-Api-Key`, `X-Goog-Api-Key` and `Xi-Api-Key`; see [Virtual keys](https://langwatch.ai/docs/ai-gateway/virtual-keys.md#the-key-format-and-how-to-send-it).

## Check it worked

Run the chat completions request. It returns a JSON body with 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.

```bash theme={null}
curl https://gateway.langwatch.ai/v1/chat/completions \
  -H "Authorization: Bearer $LANGWATCH_VIRTUAL_KEY" \
  -H "traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5-mini",
    "messages": [{"role": "user", "content": "Say hi in one word"}]
  }'
```

The format is `00-<trace id>-<span id>-<flags>`, with a 32-character trace id and a 16-character span id in hexadecimal. In an instrumented application, inject the current context rather than writing the value by hand; see the OpenTelemetry samples in [the TypeScript SDK](https://langwatch.ai/docs/ai-gateway/sdks/typescript.md#link-the-gateway-span-to-your-trace), [the Python SDK](https://langwatch.ai/docs/ai-gateway/sdks/python.md#link-the-gateway-span-to-your-trace) and [the Go SDK](https://langwatch.ai/docs/ai-gateway/sdks/go.md#link-the-gateway-span-to-your-trace).

## 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. |

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

Add `-i` to print the response headers before the body:

```bash theme={null}
curl -i https://gateway.langwatch.ai/v1/chat/completions \
  -H "Authorization: Bearer $LANGWATCH_VIRTUAL_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "openai/gpt-5-mini", "messages": [{"role": "user", "content": "Hi"}]}'
```

| Header | Value |
| - | - |
| `X-LangWatch-Gateway-Request-Id` | The request id. Quote it to support. |
| `X-LangWatch-Budget-Warning` | Present when a budget is at 80 percent or more, for example `project:84`. |
| `Traceparent` | The gateway span in your project. |

The full list is on [Chat Completions](https://langwatch.ai/docs/ai-gateway/api/chat-completions.md#response-headers).

## Self-hosted gateway

Replace the host with your gateway's URL, for example `https://gateway.acme.internal/v1`. Everything else is the same.

## In the browser

The gateway sends no CORS headers on `/v1` unless the operator allows origins, and a virtual key in browser code is visible to every visitor. Call the gateway from your server.

## 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. |
| The gateway span is its own trace | No `traceparent` on the request. |

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.