SDKs & Tools
Use the official OpenAI and Anthropic SDKs unchanged — just point them at the zrouter gateway with your API key.
zrouter is a drop-in gateway: you keep using the official OpenAI and Anthropic SDKs, and the only changes are the base URL and the API key. An zr_<public-id>_<secret> key authenticates both OpenAI-compatible and Anthropic-compatible clients.
Drop-in quickstart#
curl -X POST "https://api.zrouter.dev/v1/chat/completions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<public-name>",
"messages": [{"role": "user", "content": "Say hello!"}]
}'Streaming#
Streaming works with the same SDKs — set stream and iterate. You are billed only for the tokens actually delivered. See Streaming & SSE for the underlying wire protocol.
from openai import OpenAI
client = OpenAI(
api_key="YOUR_API_KEY",
base_url="https://api.zrouter.dev/v1",
)
stream = client.chat.completions.create(
model="<public-name>",
messages=[{"role": "user", "content": "Say hello!"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")Cookbook#
Copy-paste recipes for the most common tasks. Each recipe is self-contained; follow the links for the full background on streaming and error handling.
Minimal chat call#
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.zrouter.dev/v1")
response = client.chat.completions.create(
model="<public-name>",
messages=[{"role": "user", "content": "Say hello!"}],
)
print(response.choices[0].message.content)Minimal streaming#
Set stream and iterate. See Streaming & SSE for the wire protocol and SDK examples with usage tracking.
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.zrouter.dev/v1")
stream = client.chat.completions.create(
model="<public-name>",
messages=[{"role": "user", "content": "Say hello!"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")Error handling with retry#
Retry only 429 and 5xx failures that happen before the first byte, with exponential backoff and jitter, capped at 3 attempts. Never retry a 402 (top up your balance instead). See Error Handling.
import random, time
from openai import OpenAI, APIStatusError
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.zrouter.dev/v1")
RETRYABLE = {429, 500, 502, 503}
def chat(prompt: str, model: str = "<public-name>") -> str:
for attempt in range(3):
try:
resp = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content or ""
except APIStatusError as err:
if err.status_code == 402:
raise # insufficient balance — never retry
if err.status_code in RETRYABLE and attempt < 2:
time.sleep(min(2 ** attempt, 8) + random.random())
continue
raiseList available models#
List the models your key can access, with their public names — use these as the model argument everywhere. Live pricing is on the pricing page and the public Model Catalog.
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.zrouter.dev/v1")
for model in client.models.list():
print(model.id)