Integration

Two protocols, one API key

AtmoRouter speaks both the OpenAI Chat Completions API and the Anthropic Messages API. Point your existing client at us and keep your code exactly as it is.

OpenAI-compatible

https://atmorouter.dev/v1

Include the /v1 suffix. Used by the OpenAI SDKs, LangChain, LiteLLM and most coding agents.

Anthropic-compatible

https://atmorouter.dev

No /v1 suffix — the Anthropic SDK and Claude Code append it themselves.

Fastest path: environment variables

Most agents and CLIs read these, so nothing in your code has to change.

Environment variables

Works with most coding agents and CLIs without touching code

bash
export OPENAI_BASE_URL="https://atmorouter.dev/v1"
export OPENAI_API_KEY="ar-xxxxxxxxxxxx"

# Verify the key and list every model you can call:
curl $OPENAI_BASE_URL/models -H "Authorization: Bearer $OPENAI_API_KEY"

OpenAI Chat Completions

Same request shape, same streaming, same response fields.

Python

openai — chat, streaming, tool calls

python
from openai import OpenAI

client = OpenAI(
    base_url="https://atmorouter.dev/v1",
    api_key="ar-xxxxxxxxxxxx",
)

res = client.chat.completions.create(
    model="atmo/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Explain PKCE."}],
)
print(res.choices[0].message.content)

Node.js

openai — drop-in client replacement

javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://atmorouter.dev/v1",
  apiKey: process.env.ATMOROUTER_API_KEY,
});

const res = await client.chat.completions.create({
  model: "atmo/deepseek-v4.1-flash",
  messages: [{ role: "user", content: "Explain PKCE." }],
});

Anthropic Messages

Native /v1/messages support, including the Anthropic streaming event protocol. Any model in the catalogue can be called this way, not only Claude.

Anthropic SDK

Messages API, native Claude

python
from anthropic import Anthropic

client = Anthropic(
    base_url="https://atmorouter.dev",
    api_key="ar-xxxxxxxxxxxx",
)

msg = client.messages.create(
    model="ag/claude-opus-4-6-thinking",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a haiku."}],
)
print(msg.content[0].text)

cURL

x-api-key header, as Anthropic expects

bash
curl https://atmorouter.dev/v1/messages \
  -H "x-api-key: ar-xxxxxxxxxxxx" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ag/claude-opus-4-6-thinking",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Hello"}]
  }'

Errors on this surface use the Anthropic error envelope, so Anthropic SDKs parse them correctly.

Streaming

Server-sent events pass through byte-for-byte. Exact token usage arrives on the final frame, and that is what you are billed on.

Streaming with usage

SSE passthrough — usage on the final frame, never a character estimate

python
stream = client.chat.completions.create(
    model="atmo/deepseek-v4.1-flash",
    messages=[{"role": "user", "content": "Count to five"}],
    stream=True,
)

for chunk in stream:
    delta = chunk.choices[0].delta.content if chunk.choices else None
    if delta:
        print(delta, end="", flush=True)

# The frame before [DONE] carries:
#   {"usage": {"prompt_tokens": 9, "completion_tokens": 25}}
# Billing uses those exact counts.

Constants worth bookmarking

OpenAI base URL

https://atmorouter.dev/v1

Include the /v1 suffix.

Anthropic base URL

https://atmorouter.dev

SDK appends /v1 itself.

Auth header

Authorization: Bearer ar-…

x-api-key is accepted too.

Cost header

X-Atmorouter-Cost

Exact amount deducted, every response.

Start building today

Create an account, grab a key, and make your first call in minutes.