Anthropic Messages API
POST /v1/messages on sference: an Anthropic Messages-compatible endpoint for open models. Auth, streaming SSE, tool use, extended thinking, vision, usage, and the exact compatibility surface.
Anthropic Messages API
sference serves open models behind an Anthropic Messages-compatible endpoint: POST https://api.sference.com/v1/messages. Anything that already speaks the Anthropic Messages API. The anthropic Python/TypeScript SDKs, Claude Code, LangChain's ChatAnthropic, and your own client all point at sference by changing the base URL and the model id.
The request and response bodies are Anthropic-shaped. The models behind them are open-weight checkpoints from the sference catalog, running on European GPUs with the same logging and audit trail as every other endpoint.
Which endpoint should I use?
/v1/messages(this page): you already have Anthropic-shaped code, or a tool that only speaks Anthropic (Claude Code)./v1/chat/completions: you have OpenAI-shaped code. Also takesservice_tier: "flex", which/v1/messagesdoes not./v1/responses: sference-native; addsbackground: true, streams, and the 24h async window./v1/batches: thousands of rows on the 24h window.
All four share one catalog, one API key, and one billing surface. /v1/messages is realtime only; see Not supported.
Base URL and authentication
| Endpoint | POST https://api.sference.com/v1/messages |
| Base URL for Anthropic SDKs | https://api.sference.com |
| Auth | x-api-key: sk_... or Authorization: Bearer sk_... |
| Key format | sference keys (sk_...), minted in the console |
Both header styles work, so an Anthropic SDK configured with api_key (which sends x-api-key) and a client configured with a bearer token both authenticate unchanged. anthropic-version is accepted and ignored; there are no dated API versions on sference.
A ?beta=true query parameter is accepted and ignored; Claude Code sends it on every request.
Your first request
curl https://api.sference.com/v1/messages \
-H "x-api-key: $SFERENCE_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "zai-org/GLM-5.2",
"max_tokens": 1024,
"messages": [
{ "role": "user", "content": "Say hello in one sentence." }
]
}'{
"id": "msg_0f8a1c2e-...",
"type": "message",
"role": "assistant",
"model": "zai-org/GLM-5.2",
"content": [{ "type": "text", "text": "Hello, good to meet you." }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 14, "output_tokens": 9 }
}Anthropic Python SDK
from anthropic import Anthropic
client = Anthropic(
base_url="https://api.sference.com",
api_key="sk_...", # your sference key, not an Anthropic key
)
message = client.messages.create(
model="zai-org/GLM-5.2",
max_tokens=1024,
messages=[{"role": "user", "content": "Say hello in one sentence."}],
)
print(message.content[0].text)Anthropic TypeScript SDK
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://api.sference.com",
apiKey: process.env.SFERENCE_API_KEY,
});
const message = await client.messages.create({
model: "zai-org/GLM-5.2",
max_tokens: 1024,
messages: [{ role: "user", content: "Say hello in one sentence." }],
});Model ids are sference catalog ids
Pass a catalog id such as zai-org/GLM-5.2 or moonshotai/Kimi-K2.7-Code, not a Claude model name. There are no claude-* aliases; claude-sonnet-4-5 returns 400. Matching is case-insensitive, but the id must exist in your catalog. List what your key can reach with GET /v1/models, and see Models for how to choose.
Request fields
Supported
| Field | Notes |
|---|---|
model | Required. sference catalog id. |
max_tokens | Required, as in the Anthropic API. |
messages[] | Required. role is user or assistant; content is a string or a block array. |
system | String or text block array. Folded into one leading system message. |
stream | true emits Anthropic SSE; see Streaming. |
temperature | Forwarded to the engine. |
top_p | Forwarded to the engine. |
top_k | Forwarded to the engine (Anthropic-only knob; it has no OpenAI equivalent). |
stop_sequences[] | Forwarded as the engine's stop strings. |
tools[] | Anthropic-native (name + input_schema) and OpenAI-shaped (type: "function") definitions both accepted. |
tool_choice | auto, none, and required are honored (string or object form), as is OpenAI's forced-function object. Defaults to auto when tools are present. See the caveat under Tool use. |
thinking | {"type": "enabled"} / {"type": "disabled"}; see Extended thinking. |
enable_thinking | sference extension; a plain boolean, and it wins over thinking. |
Content blocks
| Block | Direction | Support |
|---|---|---|
text | in / out | Full. |
tool_use | in / out | Full; see Tool use. |
tool_result | in | Full, including content block arrays. |
thinking | in / out | Text is preserved; signature is always "". |
image | in | On vision models only; see Images. |
document, redacted_thinking, search_result, server tool blocks | in | Rejected with 400 (Unsupported content block type). |
Unknown top-level fields are ignored rather than rejected, so a client that sends metadata, service_tier, or container gets a normal response; those values simply have no effect. Unknown content block types are a hard 400, because silently dropping message content would change what the model sees.
Streaming
Set stream: true to receive Server-Sent Events in Anthropic's wire format. Tokens are streamed as the engine produces them.
curl -N https://api.sference.com/v1/messages \
-H "x-api-key: $SFERENCE_API_KEY" \
-H "content-type: application/json" \
-d '{
"model": "zai-org/GLM-5.2",
"max_tokens": 1024,
"stream": true,
"messages": [{ "role": "user", "content": "Count to five." }]
}'Events emitted, in order:
| Event | Notes |
|---|---|
message_start | usage.input_tokens is populated once the prompt is tokenized; the cache counters in this frame are placeholders. |
content_block_start | For each thinking, text, and tool_use block. |
content_block_delta | thinking_delta, signature_delta (always empty), text_delta, and input_json_delta for tool arguments. |
content_block_stop | Per block. |
message_delta | Carries the final stop_reason and the authoritative usage, including cache_read_input_tokens. |
message_stop | Terminal frame. |
ping | Keepalive while the request is queued or generating, so intermediaries do not reap a healthy connection during a long time-to-first-token. |
error | Terminal. {"type": "error", "error": {"type": "api_error", "message": "..."}}. |
Two details worth coding against:
- Tool arguments arrive as one
input_json_deltacontaining the complete JSON, not as incremental fragments. Clients that concatenate partials work fine; clients that try to parse each fragment as standalone JSON also work. cache_read_input_tokensonly appears onmessage_delta. The prefix-cache hit is not known whenmessage_startis written.
If a stream ends without a final frame, whether a timeout or a worker that dropped, the endpoint emits an error event before closing, so a client is never left hanging on an open connection.
Tool use
Anthropic-native tool definitions work as written:
{
"model": "moonshotai/Kimi-K2.7-Code",
"max_tokens": 1024,
"messages": [{ "role": "user", "content": "What files are in the repo root?" }],
"tools": [
{
"name": "list_files",
"description": "List files in a directory",
"input_schema": {
"type": "object",
"properties": { "path": { "type": "string" } },
"required": ["path"]
}
}
]
}The model replies with stop_reason: "tool_use" and a tool_use block carrying id, name, and a parsed input object. Send the result back as a tool_result block in a user turn, keyed by tool_use_id, exactly as with Anthropic.
Notes specific to sference:
- OpenAI-shaped tools are also accepted. A
tools[]entry withtype: "function"and a nestedfunction.name/function.parametersis normalized alongside the Anthropicname/input_schemaform. Mixed arrays are fine. This exists because some Anthropic-compatible clients send the OpenAI shape. tool_choiceforcing is partial.auto,none, andrequiredare normalized and honored, in string or object form, as is OpenAI's{"type": "function", "function": {"name": "..."}}. Anthropic's{"type": "any"}and{"type": "tool", "name": "..."}are forwarded to the engine unchanged and are not reliably honored; if you must force a specific tool, send the OpenAI object form.- Malformed tool arguments are repaired, not dropped. If a model emits arguments that are not valid JSON, sference retries a repair pass and, failing that, hands you
{"__malformed_arguments__": "<raw text>"}rather than an emptyinput. You always see what the model actually produced. - Tool quality tracks the model. Tool calling on open models is parser-dependent;
moonshotai/Kimi-K2.7-Codeandzai-org/GLM-5.2are the strongest agentic choices in the catalog today.
Extended thinking
Reasoning models return their chain of thought as a thinking block ahead of the text block, matching Anthropic's response shape.
Thinking is enabled by any of:
thinking: {"type": "enabled"}(Anthropic's spelling;{"type": "disabled"}turns it off)enable_thinking: true(sference extension, checked first, so it overridesthinking)- nothing at all, on a model whose family reasons by default (Qwen, DeepSeek-R1, Kimi, MiniMax, GLM, Hy3). Anthropic clients omit
thinkingfor third-party models, so sference defaults it on where the model expects it.
Models the catalog marks as non-reasoning always run with thinking off, even if you ask for it; forcing a <think> block on a model that has none makes the decoder treat the entire reply as reasoning and return empty content.
Signatures are empty
thinking blocks come back with signature: "". Anthropic's cryptographic thinking signatures are not implemented, and redacted_thinking blocks are not produced. sference re-injects inbound thinking text on multi-turn requests, but a client that validates signatures will not find a valid one.
budget_tokens, thinking: {"type": "adaptive"}, effort, and display are accepted and ignored; use max_tokens to bound total output.
Images
Image blocks are honored on vision-capable catalog models (Qwen/Qwen3-VL-30B-A3B-Instruct today). Both base64 and url sources work, in user turns and inside tool_result content.
On a text-only model, sference does not fail the request. Image blocks are replaced with [image omitted: this model has no vision], a system notice tells the model it has no vision, and a user-turn reminder discourages retrying screenshot tools. This keeps agent loops, which happily attach screenshots, from spinning on a capability the model does not have. If you need vision, pick a vision model; if you get the sentinel, that is why.
Response shape
{
"id": "msg_<request-uuid>",
"type": "message",
"role": "assistant",
"model": "zai-org/GLM-5.2",
"content": [
{ "type": "thinking", "thinking": "...", "signature": "" },
{ "type": "text", "text": "..." },
{ "type": "tool_use", "id": "toolu_...", "name": "list_files", "input": { "path": "." } }
],
"stop_reason": "end_turn",
"usage": { "input_tokens": 812, "output_tokens": 143, "cache_read_input_tokens": 640 }
}idismsg_plus the sference request id, the same id you look up in the console and inGET /control/v1/activity/{request_id}. That makes every Anthropic-shaped call traceable in the audit trail without extra bookkeeping.stop_reasonistool_usewhen the turn ends in a tool call,max_tokenswhen the completion was truncated, otherwiseend_turn.usage.cache_read_input_tokensappears when the prefix cache served part of the prompt; cached input tokens are billed at the lower cached rate. There is nocache_creation_input_tokens; caching is automatic and never billed as a write.stop_sequenceis not returned on non-streaming responses (streamingmessage_deltacarriesstop_sequence: null).
Errors
HTTP status codes follow the usual semantics, but error bodies are sference-shaped, not Anthropic-shaped:
{ "status_code": 400, "detail": "Unsupported content block type: 'document'", "extra": {} }Anthropic SDKs still raise the right exception class from the status code, but error.type / error.message will not be populated the way they are against api.anthropic.com. Read detail. (SSE error events during a stream are Anthropic-shaped.)
| Status | Cause |
|---|---|
| 400 | Unknown model, unsupported content block, malformed body, image that failed validation or fetch. |
| 401 | Missing or revoked key. |
| 402 | Team balance exhausted (no negative balance allowance). |
| 504 | Inference did not complete within the sync wait (600s default). The request is cancelled server-side, so no work is billed after the timeout. |
Not supported
/v1/messages is a realtime endpoint. Anything queued, discounted, or bulk lives on the other surfaces:
Not on /v1/messages | Use instead |
|---|---|
service_tier: "flex" (ignored here) | /v1/chat/completions or /v1/responses; see processing modes |
| Background / async execution | POST /v1/responses with background: true |
| Bulk jobs on the 24h window | POST /v1/batches |
POST /v1/messages/count_tokens | Not implemented; read usage.input_tokens off a real response |
| Batches, Files, Models list in Anthropic's shape | sference-native /v1/batches, /v1/models |
Prompt caching controls (cache_control blocks, anthropic-beta headers) | Prefix caching is automatic; hits are reported as cache_read_input_tokens |
| MCP connectors, web search, code execution, computer use | Not implemented; server-side tools are Anthropic-hosted |
Citations, document blocks, PDF input | Not implemented |
Thinking signatures, redacted_thinking | Not implemented; see Extended thinking |
Differences from api.anthropic.com at a glance
| Anthropic | sference /v1/messages | |
|---|---|---|
| Models | claude-* | sference catalog ids (open weights, pinned) |
| Auth | x-api-key | x-api-key or Authorization: Bearer |
| Versioning | anthropic-version required | Accepted and ignored |
| Unknown top-level fields | Rejected | Ignored |
| Error body | {"type": "error", "error": {...}} | {"status_code", "detail", "extra"} |
| Thinking signatures | Cryptographically signed | Always "" |
| Prompt caching | Explicit cache_control | Automatic prefix cache, read-side reporting only |
| Processing tiers | Standard / batch / priority | Realtime only on this endpoint |
| Data residency | US | European GPUs, audit trail on every request |
Next steps
Claude Code on sference
Run Claude Code against open models: one-command launch, hybrid routing, manual config.
Models
Catalog ids, pinning, and which checkpoints are strongest for agentic tool use.
API Reference
Generated schemas for /v1/messages and every other operation.
Quickstart
API keys, the CLI, and your first request on any endpoint.
Responses & streams
Realtime and async responses, flex processing, server-sent events, and streaming IDs under /v1/responses and /v1/streams.
Claude Code on sference
Run Claude Code against open models on sference: one-command launch with hybrid routing, manual ANTHROPIC_BASE_URL config, model recommendations, and known limits.