Messages API (Anthropic format)
POST /v1/messages — the Anthropic Messages API on open models, so Claude Code and the Anthropic SDKs work by changing the base URL.
POST https://paraloncloud.com/v1/messages accepts the request Claude Code
and the Anthropic SDKs send and answers in the Message shape, served by the
same open models as chat completions.
A client written for Claude works by changing the base URL and the key, with
no router in between.
Claude Code
Set these and start claude:
export ANTHROPIC_BASE_URL=https://paraloncloud.com
export ANTHROPIC_AUTH_TOKEN=sk-your-key
export ANTHROPIC_MODEL=qwen3.8-27b
export ANTHROPIC_SMALL_FAST_MODEL=qwen3.8-27b
export ANTHROPIC_DEFAULT_HAIKU_MODEL=qwen3.8-27b
export ANTHROPIC_DEFAULT_SONNET_MODEL=qwen3.8-27b
export ANTHROPIC_DEFAULT_OPUS_MODEL=qwen3.8-27b
claude
All the model variables matter. Claude Code sends side requests, such as a
title for the session, to models other than the main one. With only the
first three set we saw one of them go out under a Claude model name and come
back "model not found"; with all five, every request of the session asked
for qwen3.8-27b and was answered.
What we measured with Claude Code 2.1.296 on 13 October 2026: a folder with
a slugify.js that has a bug and three tests, two failing, and a prompt
asking it to run the tests, find the bug, fix it and run them again. Three
runs, all fixed, 3 of 3 tests passing, in 5 to 8 turns and 27 to 55 seconds.
That is one short task; a long session has not been measured. The runs, what
Claude Code sends and the two requests we refused on the first day are
written up in Claude Code on an open model, no router.
Two things to know:
- The context window is 131,072 tokens. Claude Code does not know this
model and assumes more. In a long session it may be refused before it
thinks to compact; compact earlier by hand with
/compact. - Ignore the cost Claude Code prints. It has no price list for the model. What was charged is on Inference usage.
Anthropic SDK
import anthropic
client = anthropic.Anthropic(base_url="https://paraloncloud.com", api_key="sk-your-key")
message = client.messages.create(
model="qwen3.8-27b",
max_tokens=200,
system="You answer in one sentence.",
messages=[{"role": "user", "content": "What is a KV cache?"}],
)
print(message.content[0].text)
The key is read from x-api-key, the header the SDK sends, or from
Authorization: Bearer.
What is supported
system | a string, or text blocks |
| Content blocks | text, image (base64 or URL, on vision models), tool_use, tool_result |
| Tools | tools with a name and an input_schema, which your client runs; tool_choice auto, any, tool, none |
| Sampling | max_tokens, temperature, top_p, top_k, stop_sequences |
| Streaming | message_start, content_block_start / content_block_delta / content_block_stop, message_delta, message_stop |
| Thinking | off unless the request asks for it (thinking.type enabled or adaptive); the reasoning then comes back in thinking blocks |
| Usage | input_tokens, output_tokens, and cache_read_input_tokens for what the worker read from its prompt cache |
stop_reason is end_turn, max_tokens or tool_use.
cache_control is accepted and ignored: prompt prefixes are cached
automatically, and a repeated prefix shows up in cache_read_input_tokens
without being marked.
What is not
Each of these is answered with a 400 that names the field:
- Server tools (web search, code execution, computer use): they run on Anthropic's side. Tools your client runs itself work.
documentblocks. Send the text.POST /v1/messages/count_tokensdoes not exist.
Errors come in Anthropic's envelope: {"type": "error", "error": {"type": "...", "message": "..."}}.
Requests are metered and billed as chat requests on the same model, at the same price.