Anthropic Messages API
Point the native Anthropic SDK straight at Mizan — same key, same wallet, same 11 providers as /v1/chat/completions, reached through Anthropic's own request/response/SSE shape instead of OpenAI's. No translating proxy required.
Make a request
Get a key from Mizan Keys and fund your wallet exactly as in the Quickstart. Auth uses x-api-key — the Anthropic SDK's default header — so a plain baseURL override is all that's needed. Authorization: Bearer mizan_rt_... also works, on this endpoint and on /v1/chat/completions.
https://api.app-mizan.comEndpointPOST /v1/messagesAuthx-api-key: mizan_rt_...One real difference from /v1/chat/completions: max_tokens is required on every request, matching the native Anthropic Messages API.
curl https://api.app-mizan.com/v1/messages \
-H "x-api-key: mizan_rt_..." \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"messages": [{ "role": "user", "content": "Say hi in five words." }]
}'import Anthropic from "@anthropic-ai/sdk"
const mizan = new Anthropic({
baseURL: "https://api.app-mizan.com",
apiKey: process.env.MIZAN_KEY, // "mizan_rt_..."
})
const message = await mizan.messages.create({
model: "claude-sonnet-4-5",
max_tokens: 1024,
messages: [{ role: "user", content: "Say hi in five words." }],
})
console.log(message.content)from anthropic import Anthropic
mizan = Anthropic(
base_url="https://api.app-mizan.com",
api_key=os.environ["MIZAN_KEY"], # "mizan_rt_..."
)
message = mizan.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Say hi in five words."}],
)
print(message.content)Model routing
A bare model id (no provider prefix) — exactly what the Anthropic SDK sends by default — defaults to the anthropic provider, as in the examples above. Prefix the model with any other supported provider to route through the Anthropic wire format to a different one — the response still comes back Anthropic-shaped either way.
curl https://api.app-mizan.com/v1/messages \
-H "x-api-key: mizan_rt_..." \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-5.1",
"max_tokens": 1024,
"messages": [{ "role": "user", "content": "Say hi in five words." }]
}'auto and mizan/switchboard work here too, exactly as documented for Auto Router and Switchboard.
Streaming
Set stream: true and Mizan streams real Anthropic SSE events — message_start, content_block_start/delta/stop, message_delta, message_stop— no matter which underlying provider serves the request. The Anthropic SDK's own stream helpers work unmodified.
curl https://api.app-mizan.com/v1/messages \
-H "x-api-key: mizan_rt_..." \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"stream": true,
"messages": [{ "role": "user", "content": "Count to five." }]
}'Tool use
tools and tool_choice are fully supported, both streaming and non-streaming — tool_use blocks in a response, and tool_result blocks on a follow-up turn. This works whether the request routes to Anthropic or to any other provider through this endpoint.
{
"model": "claude-sonnet-4-5",
"max_tokens": 1024,
"tools": [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
],
"messages": [{ "role": "user", "content": "What's the weather in Beirut?" }]
}Cost & balance
Every response carries the resolved provider/model slug and per-call cost — same convention as /v1/chat/completions, just inside the standard Anthropic usage object instead of OpenAI's. The same X-Mizan-Cost-Usd/X-Mizan-Balance-After-Usd response headers are set too.
{
"id": "msg_...",
"type": "message",
"role": "assistant",
"model": "anthropic/claude-sonnet-4-5",
"content": [{ "type": "text", "text": "Hi there, hope you're well!" }],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 12,
"output_tokens": 9,
"cost": 0.000267,
"balance_after_usd": 47.499733
}
}Known limitations
Image content blocks (vision) and extended-thinking blocks aren't supported yet — a request containing either is rejected with a 400 rather than silently dropped, so you're never billed for content that wasn't actually forwarded. Your own cache_control hints are accepted but not preserved through the translation — Mizan applies its own automatic caching on top of your system prompt and tools regardless, see Prompt caching. Gemini's image-generation models are also rejected with a 400 here — they're only reachable through /v1/chat/completions.
Errors
Errors use Anthropic's own envelope shape — the same HTTP status codes documented for /v1/chat/completions, just wrapped differently so the Anthropic SDK's typed exceptions resolve correctly.
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "..."
}
}| Code | When |
|---|---|
| 400 | Missing model/max_tokens, an unsupported content block (image, thinking, etc.), or an invalid "models" fallback list. |
| 401 | Missing, invalid, or revoked Mizan key. |
| 402 | Wallet balance is insufficient, or the wallet is frozen (top up to resume). |
| 403 | This key's own usage limit has been reached (independent of wallet balance). |
| 422 | The requested model has no pricing configured for it — check GET /v1/models for the current active model IDs before guessing. |
| 429 | Rate limit exceeded for this key (300 requests/minute by default). |
| 502 | The upstream provider request itself failed (network/timeout). |
| 503 | That provider isn't configured on this deployment yet. |