# OpenAI-compatible API

URL: https://docs.router.ezat.io/openai/base-url

> Base URL, authentication, endpoint mapping and SDK setup for tools and code that speak OpenAI's API format.

## When to use this page

Your code or tool speaks only OpenAI's API format (the `openai` SDKs, LangChain's OpenAI client, editors that take an OpenAI base URL). This page gives the base URL, the endpoints that exist and how to point the SDKs at them. [Chat Completions](https://docs.router.ezat.io/openai/chat-completions.md) covers the request and response in detail.

## Base URL and key

| Setting | Value |
| --- | --- |
| Base URL | `https://api.router.ezat.io/openai/v1` |
| API key | Your EZAT key (`ezat_sk_…`), sent as `Authorization: Bearer <key>` |
| Model | An id from [Models](https://docs.router.ezat.io/models.md), for example `anthropic/claude-sonnet-5-5` |

The base URL already ends in `/v1`. Clients add `/chat/completions` and `/models` to it. `https://api.router.ezat.io/v1` is the [Anthropic-format API](https://docs.router.ezat.io/anthropic/messages.md) and has no `/chat/completions`.

The OpenAI-compatible API uses the same keys, models, balance, limits and routing as the Anthropic-format API. A conversation costs the same through either one, and both show up together on the dashboard's Usage page.

## Endpoints

| OpenAI path | EZAT URL | Status |
| --- | --- | --- |
| `POST /v1/chat/completions` | `https://api.router.ezat.io/openai/v1/chat/completions` | Supported, streaming and not |
| `GET /v1/models` | `https://api.router.ezat.io/openai/v1/models` | Supported |
| `GET /v1/models/{model}` | `https://api.router.ezat.io/openai/v1/models/{model}` | Supported. Ids with a slash work as they are, and aliases resolve. |
| `POST /v1/responses` (Responses API) | | Not available |
| `POST /v1/embeddings` | | Not available |
| `/v1/images/…` (image generation) | | Not available |
| `/v1/audio/…` (speech, transcription) | | Not available |
| `/v1/files`, `/v1/batches` | | Not available |
| `POST /v1/completions` (legacy completions) | | Not available |
| `POST /v1/moderations` | | Not available |

A path that isn't available returns `404` with `{"statusCode": 404, "message": "Cannot POST /openai/v1/responses"}`. That body isn't OpenAI's error format, so SDKs show it as a plain not-found error.

Tools that only call the Responses API (for example recent versions of OpenAI's Codex CLI) don't work yet. See [OpenAI-format tools](https://docs.router.ezat.io/tools/openai-tools.md).

## Set up the SDKs

```python tab="Python" test
import os

from openai import OpenAI

client = OpenAI(
    base_url="https://api.router.ezat.io/openai/v1",
    api_key=os.environ["EZAT_API_KEY"],
)

completion = client.chat.completions.create(
    model="anthropic/claude-sonnet-5-5",
    max_tokens=64,
    messages=[{"role": "user", "content": "Say hello in five words."}],
)
print(completion.choices[0].message.content)
```

```ts tab="Node.js" test
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.router.ezat.io/openai/v1",
  apiKey: process.env.EZAT_API_KEY,
});

const completion = await client.chat.completions.create({
  model: "anthropic/claude-sonnet-5-5",
  max_tokens: 64,
  messages: [{ role: "user", content: "Say hello in five words." }],
});
console.log(completion.choices[0].message.content);
```

```bash tab="curl" test
curl --fail-with-body https://api.router.ezat.io/openai/v1/chat/completions \
  -H "Authorization: Bearer $EZAT_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-5-5",
    "max_tokens": 64,
    "messages": [{"role": "user", "content": "Say hello in five words."}]
  }'
```

Install the SDK with `pip install openai` or `npm install openai`.

## Environment variables

The `openai` SDKs for Python and Node.js read `OPENAI_BASE_URL` and `OPENAI_API_KEY` when you don't pass `base_url` / `baseURL` and `api_key` / `apiKey`. Many tools built on them read the same two variables:

```bash
export OPENAI_BASE_URL="https://api.router.ezat.io/openai/v1"
export OPENAI_API_KEY="$EZAT_API_KEY"
```

These variables also redirect every other program in that shell that uses them. Set them per project or per command if you also call OpenAI itself.

## Model ids

Use the same ids as on the Anthropic-format API: canonical `author/model` ids, or their aliases. The [Models](https://docs.router.ezat.io/models.md) page lists them, and so does the API:

```bash tab="curl" test
curl --fail-with-body https://api.router.ezat.io/openai/v1/models \
  -H "Authorization: Bearer $EZAT_API_KEY"
```

```json
{
  "object": "list",
  "data": [
    { "id": "anthropic/claude-sonnet-5-5", "object": "model", "created": 1790812800, "owned_by": "anthropic" }
  ]
}
```

The list has the models your key can use. The response's `model` field echoes the name you sent. An unknown model returns `404` with code `model_not_found`.

## Errors

Errors use OpenAI's envelope, `{"error": {"message", "type", "param", "code"}}`, so the SDKs raise their usual exceptions. The statuses are those of the Anthropic-format API except one: an overloaded model is `503`, not `529`. The types and codes are OpenAI's, for example `insufficient_quota` for an empty balance (`402`) and `model_not_found` for an unknown model (`404`). The full mapping is in [Chat Completions](https://docs.router.ezat.io/openai/chat-completions.md).

## For AI agents

1. Base URL `https://api.router.ezat.io/openai/v1`, exactly. Don't use `https://api.router.ezat.io/v1` for OpenAI-format clients.
2. API key: the EZAT key from `EZAT_API_KEY`, as `Authorization: Bearer`. With the SDKs, pass it as `api_key` / `apiKey`, or set `OPENAI_API_KEY`.
3. Model: an id from `GET https://api.router.ezat.io/openai/v1/models`.
4. Only Chat Completions and the models endpoints exist. Don't configure a tool that requires the Responses API, embeddings, image generation or audio.