Use Xantly with the Anthropic Python SDK
Xantly ships a byte-accurate /v1/messages endpoint. The official anthropic Python SDK points at it with base_url, messages.create, streaming, tool_use, prompt caching all work.
Xantly ships a byte-accurate /v1/messages endpoint that mirrors Anthropic's Messages API. Point the official anthropic Python SDK at it and everything, messages.create, streaming, tool use, prompt caching, vision, works untouched. No SDK fork needed.
Prerequisites
- Python 3.8+
pip install anthropic(version 0.30.0+)- A Xantly API key, create one
Setup
from anthropic import Anthropic
client = Anthropic(
base_url="https://api.xantly.com",
api_key="xantly_sk_...",
)
Note: base_url is the bare host: no /v1 suffix. The Anthropic SDK appends /v1/messages on its own.
Env-var form:
export ANTHROPIC_BASE_URL=https://api.xantly.com
export ANTHROPIC_API_KEY=xantly_sk_...
messages.create
resp = client.messages.create(
model="anthropic/claude-sonnet-4.6",
max_tokens=1024,
messages=[{"role": "user", "content": "Write a bubble sort in Python."}],
)
print(resp.content[0].text)
You can also use Xantly aliases:
resp = client.messages.create(
model="xantly/auto-quality",
max_tokens=1024,
messages=[...],
)
Streaming
with client.messages.stream(
model="anthropic/claude-sonnet-4.6",
max_tokens=1024,
messages=[{"role": "user", "content": "Stream a haiku."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
Xantly preserves every Anthropic SSE event exactly, message_start, content_block_start, content_block_delta, content_block_stop, message_delta, message_stop. No custom handling.
Tool use (tool_use blocks)
tools = [{
"name": "get_weather",
"description": "Get weather for a city.",
"input_schema": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
}]
resp = client.messages.create(
model="anthropic/claude-sonnet-4.6",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Weather in Paris?"}],
)
for block in resp.content:
if block.type == "tool_use":
print(block.name, block.input)
Prompt caching
Anthropic's prompt caching works as-is. Add the cache_control marker; Xantly forwards it:
resp = client.messages.create(
model="anthropic/claude-sonnet-4.6",
max_tokens=1024,
messages=[{
"role": "user",
"content": [
{
"type": "text",
"text": "<large context here>",
"cache_control": {"type": "ephemeral"},
},
{"type": "text", "text": "What's the summary?"},
],
}],
extra_headers={"anthropic-beta": "prompt-caching-2024-07-31"},
)
print(resp.usage.cache_creation_input_tokens)
Xantly's own L1/L2 semantic cache runs in addition to Anthropic's prompt cache, Anthropic caches within a single provider; Xantly caches across providers and sessions.
Async client
import asyncio
from anthropic import AsyncAnthropic
aclient = AsyncAnthropic(
base_url="https://api.xantly.com",
api_key="xantly_sk_...",
)
async def main():
resp = await aclient.messages.create(
model="xantly/auto-quality",
max_tokens=512,
messages=[{"role": "user", "content": "Ping"}],
)
print(resp.content[0].text)
asyncio.run(main())
Model choice
| Model ID | When |
|---|---|
anthropic/claude-sonnet-4.6 | Pinned Claude, best default via Messages API. |
anthropic/claude-opus-4.5 | Highest-quality Claude. |
anthropic/claude-haiku-4.5 | Fast + cheap Claude. |
xantly/auto-quality | BaRP T1, may pick Claude, GPT, or others, responses translated back into Messages shape. |
xantly/auto-value | Balanced. |
Verify
resp = client.messages.create(
model="anthropic/claude-haiku-4.5",
max_tokens=32,
messages=[{"role": "user", "content": "say pong"}],
)
print(resp.content[0].text)
Open your Xantly dashboard, the call logs with model, cache status, and USD cost.
What you get
- Byte-accurate Messages API compatibility. Including betas (prompt caching, PDFs, computer-use).
- Waterfall fallback. Anthropic overloaded? Xantly retries on GPT/Groq and translates the response back into Messages shape. Your client code never sees the swap.
- Memory across sessions.
extra_headers={"X-Xantly-Memory-Mode": "recall"}. - Cost per turn. Every call logged with routing decision + cost.
- Cross-provider tool translation. When Xantly falls back to GPT, tool-use blocks are translated both ways.
Gotchas
base_url has no /v1. Anthropic's SDK appends the path. Use the bare host, https://api.xantly.com, not https://api.xantly.com/v1.
Anthropic SDK pins API versions via anthropic-version header. Xantly respects the header and forwards to the underlying provider. Default (2023-06-01) works fine.
Streaming with iterators. with client.messages.stream(...) (context manager) is the stable API. Don't use the deprecated stream=True kwarg.
Beta headers. anthropic-beta: prompt-caching-2024-07-31, pdfs-2024-09-25, computer-use-2024-10-22 all pass through.
Next steps
- Anthropic SDK (TypeScript), the Node.js equivalent.
- Claude Code, Anthropic's CLI tool with the same pattern.
- OpenAI SDK (Python), if you'd rather use the OpenAI shape.
- Memory & Context, how L3 memory extends Claude sessions.