MonoRouter API Compatibility: What Works and What Doesn't
A complete reference of which Anthropic API features MonoRouter supports, with workarounds for the few that don't apply.
MonoRouter aims to be a drop-in replacement for the Anthropic API. In practice, that means supporting the Messages API surface that developer tools actually use. Here's the complete compatibility picture — with code examples for every major feature.
Compatibility Matrix
| Feature | Status | Notes |
|---|---|---|
| Messages API (create) | ✅ Full | All content types, roles, system prompts |
| Streaming (SSE) | ✅ Full | All event types forwarded in real time |
| Tool use | ✅ Full | Definitions, tool_use, tool_result, parallel calls |
| Model selection | ✅ Full | Opus, Sonnet, Haiku via model parameter |
| Temperature / top_p | ✅ Full | Sampling params pass through unchanged |
| Max tokens | ✅ Full | Respects your specified limit |
| Stop sequences | ✅ Full | Custom stop sequences work as expected |
| System prompts | ✅ Full | Single and multi-block |
| Image inputs | ✅ Full | Base64 and URL content blocks |
| Extended thinking | ⚠️ Caveat | Works — set client timeout ≥ 300s |
| Token counting | ⚠️ Caveat | Accurate, but from subscription session |
| Rate limit headers | ⚠️ Caveat | Reflects MonoRouter pool, not Anthropic API |
| Batches API | ❌ N/A | Designed for API-credit bulk processing |
| Admin API | ❌ N/A | Organizational management for API accounts |
Messages API
The core endpoint works identically. Here's a request and response through MonoRouter:
import anthropic
client = anthropic.Anthropic(
api_key="mr_live_abc123",
base_url="https://api.monorouter.dev/v1",
)
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=256,
system="You are a helpful coding assistant.",
messages=[
{"role": "user", "content": "What does `**kwargs` do in Python?"}
],
)
print(response.content[0].text)
print(f"Usage: {response.usage.input_tokens} in / {response.usage.output_tokens} out")
The response object has the same shape as the direct API — id, type, role, content, model, stop_reason, and usage fields are all present and accurate.
Streaming
Full SSE streaming with all event types:
with client.messages.stream(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{"role": "user", "content": "Explain monads in 100 words"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
# Event types forwarded:
# message_start → content_block_start → content_block_delta (×N)
# → content_block_stop → message_delta → message_stop
The raw SSE frames are identical to what the Anthropic API produces. MonoRouter doesn't buffer, batch, or rewrite events.
Tool Use
Full tool use protocol — definitions, responses, results, and parallel calls:
tools = [{
"name": "lookup_user",
"description": "Look up a user by email",
"input_schema": {
"type": "object",
"properties": {
"email": {"type": "string", "description": "User email address"}
},
"required": ["email"]
}
}]
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Find the user with email [email protected]"}],
)
# response.stop_reason == "tool_use"
# response.content[0].type == "tool_use"
# response.content[0].name == "lookup_user"
# response.content[0].input == {"email": "[email protected]"}
Every field — tool_use_id, name, input, is_error — passes through MonoRouter unchanged.
Image Inputs
Base64 and URL image content blocks both work:
import base64
with open("screenshot.png", "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
messages=[{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_data,
},
},
{
"type": "text",
"text": "What's in this screenshot?"
}
],
}],
)
Multi-Block System Prompts
Complex system prompts with multiple content blocks are supported:
response = client.messages.create(
model="claude-sonnet-4-20250514",
max_tokens=1024,
system=[
{"type": "text", "text": "You are a code reviewer for a Python project."},
{"type": "text", "text": "Focus on: security issues, performance problems, and code style."},
{"type": "text", "text": "Always cite the specific line numbers in your feedback."},
],
messages=[{"role": "user", "content": diff_text}],
)
SDK Compatibility
Every official Anthropic SDK supports custom base URLs:
Python:
client = anthropic.Anthropic(
base_url="https://api.monorouter.dev/v1"
)
# or via env: ANTHROPIC_BASE_URL
TypeScript:
const client = new Anthropic({
baseURL: "https://api.monorouter.dev/v1"
});
// or via env: ANTHROPIC_BASE_URL
cURL:
curl https://api.monorouter.dev/v1/messages \
-H "Content-Type: application/json" \
-H "x-api-key: mr_live_abc123" \
-H "anthropic-version: 2023-06-01" \
-d '{
"model": "claude-sonnet-4-20250514",
"max_tokens": 256,
"messages": [{"role": "user", "content": "Hello"}]
}'
No forks, no patches, no custom clients. The official SDKs work as-is — just point them at MonoRouter.
Extended Thinking
Extended thinking works but requires generous timeouts. Claude's internal reasoning can take 60–120 seconds for complex problems:
client = anthropic.Anthropic(
base_url="https://api.monorouter.dev/v1",
timeout=300.0, # 5 minutes — important for extended thinking
)
response = client.messages.create(
model="claude-opus-4-20250514",
max_tokens=16384,
thinking={
"type": "enabled",
"budget_tokens": 10000,
},
messages=[{"role": "user", "content": "Prove that the square root of 2 is irrational."}],
)
for block in response.content:
if block.type == "thinking":
print(f"[Thinking]: {block.thinking[:200]}...")
elif block.type == "text":
print(f"\n{block.text}")
What's Not Supported
These Anthropic API features don't apply in the MonoRouter model:
- Batches API — designed for bulk processing with API credits. Not relevant when routing through subscriptions.
- Admin API — organizational management for Anthropic API accounts. MonoRouter has its own dashboard.
- Usage-based billing metadata — there's nothing to bill. You're using your subscription.
- API key management — your MonoRouter key is separate from Anthropic API keys.
None of these affect typical developer tooling. The features that Claude Code, Cursor, LangChain, and custom agents actually use — messages, streaming, tools — are fully supported.