Anthropic Messages API
ARK also speaks Anthropic's Messages API, so tools and agents built for Claude can run on open models served from Europe. Same key, same models, a different base URL.
API reference: Messages
Set up the SDK
Point the SDK at https://api.ark-labs.cloud/api/anthropic (it adds /v1/messages itself) and pass your ARK key as auth_token, so it is sent as Authorization: Bearer. ARK does not read x-api-key or require anthropic-version.
import os
import anthropic
client = anthropic.Anthropic(
base_url="https://api.ark-labs.cloud/api/anthropic",
auth_token=os.environ["ARK_API_KEY"],
)
message = client.messages.create(
model="arklabsai/Qwen3.5-122B-A10B",
max_tokens=1024,
system="You are a concise assistant.",
messages=[{"role": "user", "content": "Why does data residency matter for a European bank?"}],
)
print(message.content[0].text)import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://api.ark-labs.cloud/api/anthropic",
authToken: process.env.ARK_API_KEY,
});
const message = await client.messages.create({
model: "arklabsai/Qwen3.5-122B-A10B",
max_tokens: 1024,
system: "You are a concise assistant.",
messages: [{ role: "user", content: "Why does data residency matter for a European bank?" }],
});
console.log(message.content[0].text);curl https://api.ark-labs.cloud/api/anthropic/v1/messages \
-H "Authorization: Bearer $ARK_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "arklabsai/Qwen3.5-122B-A10B",
"max_tokens": 1024,
"system": "You are a concise assistant.",
"messages": [{"role": "user", "content": "Why does data residency matter for a European bank?"}]
}'{
"id": "msg_01J9…",
"type": "message",
"role": "assistant",
"model": "arklabsai/Qwen3.5-122B-A10B",
"content": [{ "type": "text", "text": "Because supervisors expect…" }],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 31,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0,
"output_tokens": 212,
"output_tokens_details": { "thinking_tokens": 0 },
"service_tier": "standard"
}
}Request fields
model, messages and max_tokens are required. system (a string or text blocks), temperature (0–1, default 0.6), top_p, top_k, stop_sequences (up to 4), stream, tools, tool_choice, thinking and output_config work as in Anthropic's API. metadata, service_tier, cache_control and a few others are accepted without effect. See the API reference for every field.
Content blocks
text;imagewith abase64orurlsource (vision models only);documentwith a plain-text source;search_result.tool_useandtool_resultfor tool conversations.thinkingblocks from earlier turns are accepted and dropped.- PDF documents and audio blocks are not supported and return
400.
If the last message is an assistant turn, Qwen models continue it (prefill), and only the continuation is returned.
Streaming
With "stream": true, ARK sends Anthropic's named events: message_start, content_block_start, ping, content_block_delta (text_delta, thinking_delta, input_json_delta), content_block_stop, message_delta with the stop reason and final usage, and message_stop.
with client.messages.stream(
model="arklabsai/Qwen3.6-35B-A3B",
max_tokens=1024,
messages=[{"role": "user", "content": "Write a short poem about the Oder river."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Thinking
Turn reasoning on with thinking. The thinking arrives as a thinking block before the answer, and usage.output_tokens_details.thinking_tokens counts it.
thinking | Result |
|---|---|
absent, or {"type": "disabled"} | No thinking. |
{"type": "enabled", "budget_tokens": 8192} or more | Thinking, high level. |
{"type": "enabled", "budget_tokens": 1024 … 8191} | Thinking, medium level. |
{"type": "adaptive"} | Thinking, medium level. |
budget_tokens selects the level; it does not cap the thinking. Use max_tokens to bound the total. output_config.effort (low … max) is honoured too. As on the OpenAI route, offering tools turns thinking off on the Qwen models.
Tools
message = client.messages.create(
model="arklabsai/Qwen3.6-35B-A3B",
max_tokens=1024,
tools=[{
"name": "get_weather",
"description": "Current weather for a city.",
"input_schema": {"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
}],
messages=[{"role": "user", "content": "Do I need an umbrella in Gdańsk?"}],
)
tool_use = next(b for b in message.content if b.type == "tool_use")
print(tool_use.name, tool_use.input) # get_weather {'city': 'Gdańsk'}- Return results in a
usermessage withtool_resultblocks;is_error: truetells the model the tool failed. tool_choice:auto,any,{"type": "tool", "name": …}ornone;disable_parallel_tool_uselimits the reply to one call.- Only your own (client) tools are supported. Anthropic's server tools, such as web search or code execution, return
400.
Count tokens
POST /api/anthropic/v1/messages/count_tokens returns the exact number of input tokens a request would use, including the system prompt, tools and images. It is free.
count = client.messages.count_tokens(
model="arklabsai/Qwen3.5-122B-A10B",
messages=[{"role": "user", "content": "Why does data residency matter for a European bank?"}],
)
print(count.input_tokens)Usage and stop reasons
input_tokenscounts the uncached part of the prompt andcache_read_input_tokensthe part served from ARK's prefix cache; their sum is the full prompt.cache_creation_input_tokensis always 0.stop_reasonisend_turn,max_tokens,stop_sequenceortool_use.- Every response has a
request-idheader; error bodies carry the samerequest_id.
Models
GET /api/anthropic/v1/models lists the models in Anthropic's format, paged with limit, after_id and before_id. Use the chat and vision models with /messages.