Skip to content
AZRouter.dev

API

Anthropic Messages

POST /v1/messages speaks Anthropic's Messages format for every text model on sale.

POST /v1/messages takes Anthropic's Messages request and returns Anthropic's response and stream events. It's the route Claude Code and the Anthropic SDKs use. The gateway converts the request for the model you name, so every text model on sale answers here, not only Claude models.

Base URLhttps://api.azrouter.dev (no /v1; the client adds /v1/messages)
Key headerx-api-key: <key> or Authorization: Bearer <key>
Version headeranthropic-version: 2023-06-01

Claude models

Claude Opus 5.5 (anthropic/claude-opus-5.5) and Claude Haiku 5.5 (anthropic/claude-haiku-5.5) are on sale; any other text model's slug works in model too. Their prompt cache lasts 5 minutes and caches only cache_control markers on content blocks: see Prompt caching.

Example

Shell
curl https://api.azrouter.dev/v1/messages \
  -H "x-api-key: $AZROUTER_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen/qwen3.8-flash",
    "max_tokens": 200,
    "messages": [{"role": "user", "content": "Reply with exactly: Hello from AZRouter"}]
  }'

Response (abridged):

JSON
{
  "type": "message",
  "role": "assistant",
  "content": [
    {"type": "thinking", "thinking": "We need to respond to user: \"Reply with exactly: Hello from AZRouter\". ..."},
    {"type": "text", "text": "Hello from AZRouter"}
  ],
  "stop_reason": "end_turn",
  "model": "qwen/qwen3.8-flash",
  "usage": {"input_tokens": 69, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "output_tokens": 42}
}

A reasoning model's thinking arrives as a thinking block before the text block.

Anthropic SDK

Point the SDK at the base URL without /v1:

Python
import os
from anthropic import Anthropic

client = Anthropic(
    base_url="https://api.azrouter.dev",
    api_key=os.environ["AZROUTER_API_KEY"],
)

message = client.messages.create(
    model="qwen/qwen3.8-flash",
    max_tokens=200,
    messages=[{"role": "user", "content": "Reply with exactly: Hello from AZRouter"}],
)
print(next(block.text for block in message.content if block.type == "text"))

Streaming

Add "stream": true to get Anthropic's server-sent events: message_start, content_block_start, content_block_delta, content_block_stop, message_delta and message_stop.

Shell
curl -N https://api.azrouter.dev/v1/messages \
  -H "x-api-key: $AZROUTER_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen/qwen3.8-flash",
    "max_tokens": 200,
    "stream": true,
    "messages": [{"role": "user", "content": "Reply with exactly: Hello from AZRouter"}]
  }'

Tools

Tool definitions (tools with input_schema) and tool_use / tool_result blocks are converted in both directions, streamed or not. As on Chat Completions, only your own tools are accepted; server tools such as web search are refused with 400 unsupported_paid_feature.

Token counting is not available

POST /v1/messages/count_tokens returns 404:

Shell
curl -i https://api.azrouter.dev/v1/messages/count_tokens \
  -H "x-api-key: $AZROUTER_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"model": "qwen/qwen3.8-flash", "messages": [{"role": "user", "content": "Hello"}]}'

Claude Code treats this endpoint as optional and estimates token counts itself, so its context meter is approximate. The bill uses the token counts the model reports.