Claude SDK
VectorAxis serves Anthropic’s Messages API on its own paths (/v1/messages, /v1/messages/count_tokens, /v1/messages/batches), so the official Claude SDK, in any language, works by changing its base URL and using a VectorAxis virtual key as its API key. Requests run through the same pipeline as the OpenAI-compatible endpoint: budgets, rate limits, guardrails, the tool-result scan, caching, fallbacks, logs and cost.
import anthropic
client = anthropic.Anthropic(
base_url="https://api.vectoraxis.ai",
api_key="vk-c7d4e1f2a3b95a8b.Rq8mT2vX5nL9pW3kY7cJ1hF4dS6gB0zN2aE8uV5tQ1c", # an Anthropic virtual key
)
message = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(message.content[0].text)import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
baseURL: 'https://api.vectoraxis.ai',
apiKey: process.env.VECTORAXIS_KEY, // vk-...
});
const message = await client.messages.create({
model: 'claude-haiku-4-5',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello, Claude' }],
});curl https://api.vectoraxis.ai/v1/messages \
-H "x-api-key: vk-c7d4e1f2a3b95a8b.Rq8mT2vX5nL9pW3kY7cJ1hF4dS6gB0zN2aE8uV5tQ1c" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{"model":"claude-haiku-4-5","max_tokens":1024,"messages":[{"role":"user","content":"Hello, Claude"}]}'Every VectorAxis feature is a request header, exactly as on the OpenAI-compatible endpoint. Set them once with the SDK’s default_headers (Python) / defaultHeaders (TypeScript), or per call with extra_headers. See Request headers.
The Python and TypeScript SDKs send their API key as x-api-key; the Java SDK sends it as Authorization: Bearer. Both are accepted. In order, the gateway reads:
| Credential | What it is |
|---|---|
| x-virtual-key | A virtual key, explicitly. |
| Authorization: Bearer vk-… | A virtual key as a bearer token (ANTHROPIC_AUTH_TOKEN, the Java SDK). |
| x-config | A routing config (with x-organization). Checked before x-api-key, so the SDK’s own key header does not override it. |
| x-api-key: vk-… | A virtual key in the SDK’s usual header. |
| x-api-key (anything else) | Your own provider key, passed straight through (the direct-credential path). The provider is x-provider when set, otherwise Anthropic. |
A virtual key for another provider works too: the gateway translates the Messages request to that provider’s format and the answer back, so an application written for the Claude SDK can run on an OpenAI model by changing only its key and model.
| Feature | Notes |
|---|---|
| Streaming | stream: true returns Anthropic’s own events (message_start, content_block_delta, …, message_stop). An error after the first event (an output guardrail block included) arrives as an error event. |
| Tools | Client tools, tool_use / tool_result (with is_error, and images or PDFs inside a result), strict, and tool_choice auto / any / none / a named tool, with disable_parallel_tool_use. |
| Images and PDFs | image blocks (base64 or URL) and document blocks (base64 PDF, or plain text). |
| Extended thinking | thinking (any setting) and output_config.effort. Thinking blocks come back with their signatures and go back to Anthropic unchanged and in order, so multi-turn thinking with tools works. |
| Structured output | output_config.format with a JSON schema. |
| Stop sequences | stop_reason: stop_sequence with the matched sequence. |
| Prompt caching | cache_control on system blocks, messages, images, documents, tool results and tools, and the top-level automatic form, with ttl 5m or 1h. Below. |
| Token counting | POST /v1/messages/count_tokens. Below. |
| Message Batches | The whole Batches API. Below. |
| Beta features | The anthropic-beta header is passed to Anthropic. Below. |
| Metadata | metadata.user_id is recorded as the request’s user in Logs. |
Both endpoints hand the gateway the same request, so everything a virtual key enforces applies here:
- Key checks: status, expiry, credit limit, model allowlist, and requests and tokens per minute and day.
- Plan limits: the workspace request rate.
- Guardrails: input and output, the key’s own plus any named in x-guardrail. A block is a 422 with x-guardrail-status: BLOCK, reported as invalid_request_error.
- Tool-result scan: at the key’s own action, with x-tool-scan-status: BLOCK on a block.
- Gateway features: response caching, retries and fallbacks, routing configs, prompt attribution (x-prompt-slug), logs and cost.
Errors always come back in Anthropic’s shape, {"type":"error","error":{"type":…,"message":…}}, so the SDK raises its usual exception classes. A provider error keeps the provider’s status, type and message.
Every cache_control breakpoint reaches Anthropic on the block it was on, and the response carries Anthropic’s own usage split: cache_creation_input_tokens, cache_read_input_tokens and cache_creation by TTL. This is Anthropic’s prompt cache, separate from the gateway’s response cache: a hit still calls the model, but the cached prefix is billed at the cache rate.
message = client.messages.create(
model="claude-haiku-4-5",
max_tokens=1024,
system=[{
"type": "text",
"text": LONG_REFERENCE_TEXT,
"cache_control": {"type": "ephemeral"}, # or {"type": "ephemeral", "ttl": "1h"}
}],
messages=[{"role": "user", "content": "Summarise section 3."}],
)
print(message.usage.cache_creation_input_tokens, message.usage.cache_read_input_tokens)Cost: cache reads, cache writes and 1-hour writes are charged at the model’s own cache rates (on Claude, a read is about a tenth of the input rate and a 5-minute write 1.25 times it), the rest at the input rate. A model must see a minimum prefix before it caches anything (4,096 tokens on Haiku 4.5); shorter prefixes are not cached and report zero cache tokens.
POST /v1/messages/count_tokens returns {"input_tokens": N} from Anthropic’s own counter, for Anthropic keys and Claude on Vertex AI. It takes the same credentials and key checks as /v1/messages. Nothing is generated, so nothing is billed or logged. Another provider, or a routing config, is a 400.
count = client.messages.count_tokens(
model="claude-haiku-4-5",
system="You are a weather assistant.",
tools=[weather_tool],
messages=[{"role": "user", "content": "What is the temperature in Lisbon?"}],
)
print(count.input_tokens)The Batches API runs many Messages requests asynchronously at half the standard price, usually within minutes and always within 24 hours. Create, list, retrieve, cancel, delete and results all work through the SDK’s messages.batches.
batch = client.messages.batches.create(requests=[
{"custom_id": "ticket-1", "params": {"model": "claude-haiku-4-5", "max_tokens": 256,
"messages": [{"role": "user", "content": "Classify: 'I was charged twice.'"}]}},
{"custom_id": "ticket-2", "params": {"model": "claude-haiku-4-5", "max_tokens": 256,
"messages": [{"role": "user", "content": "Classify: 'How do I reset my password?'"}]}},
])
# later, once batch.processing_status == "ended"
for result in client.messages.batches.results(batch.id):
print(result.custom_id, result.result.type)| How it works | |
|---|---|
| Keys | A BYOK Anthropic virtual key, or your own Anthropic key. PLATFORM keys are refused: a batch is billed after it runs, which a prepaid balance cannot cover in advance. Other providers, Claude on Vertex AI and routing configs are a 400. |
| Checks | Each request is checked as a /v1/messages call would be before Anthropic sees the batch: the key against every model, the tool-result scan, and the input guardrails. A block on one request refuses the whole batch and names its custom_id. The batch counts as one request against rate limits. Output guardrails cannot run: the answers are produced later. |
| Ownership | A batch belongs to the virtual key that created it. Another key, even on the same Anthropic account, gets a 404 for it and does not see it in its list. |
| Results | Fetched through the gateway: the batch’s results_url points at VectorAxis, not at Anthropic. Reading results costs nothing. |
| Billing | Once a batch ends, VectorAxis reads its results and writes one log row per succeeded or errored request (operation_type message_batch, request id <batch id>/<custom_id>), priced at the batch rate, and charges the total to the key once. Canceled and expired requests cost nothing. This happens whether or not you fetch the results, usually within five minutes of the batch ending. |
| Delete | Allowed once a batch has ended. Its results go with it, so it is billed first. |
These are Anthropic’s batches. OpenAI’s file-based batches are /v1/batches, a separate API.
The SDK’s anthropic-beta header (its beta client, and Claude Code) is passed to Anthropic and Claude on Vertex AI on /v1/messages, count_tokens and /v1/chat/completions, retries and fallbacks included. It is never sent to another provider. A value that is not a comma-separated list of beta names (lower-case letters, digits and dashes, at most 32) is a 400 from the gateway; a well-formed name Anthropic does not know is Anthropic’s own 400.