Anthropic compatibility
POST /v1/messages implements the Anthropic Messages API shape, so Anthropic SDKs and the tools built on them, most notably Claude Code, run against MindsHub with a base-URL and auth-token change. Model names resolve through the same catalog as everywhere else, so you can point an Anthropic client at any MindsHub model: gpt, kimi, gemini-flash, not just Claude.
Claude Code
export ANTHROPIC_BASE_URL="https://api.mindshub.ai"
export ANTHROPIC_AUTH_TOKEN="$MINDSHUB_API_KEY"
claude
Three rules:
-
Use
ANTHROPIC_AUTH_TOKEN, notANTHROPIC_API_KEY. The auth-token variable sendsAuthorization: Bearer …, which is the only header MindsHub accepts.ANTHROPIC_API_KEYsendsx-api-key, which is rejected with a 401 before the request reaches the API. -
The base URL is the host only, no
/v1. The client adds the/v1/messagespath itself. -
Optional: give MindsHub its own config directory.
ANTHROPIC_AUTH_TOKENoutranks a stored claude.ai login, so this isn't required for authentication. It keeps MindsHub sessions and settings separate from your regular profile, and it is the fix if a startup401 Authorization Requiredshows Claude Code preferring its stored login anyway (reported on some 2.1.x setups):export CLAUDE_CONFIG_DIR="$HOME/.claude-mindshub"
Three cost notes for Claude Code specifically:
- Its default model maps to the
opusalias, one of the most expensive in the catalog. Pick a cheaper model in Claude Code (/model) if cost matters. - Claude Code makes heavy use of prompt caching; cache writes are billable and never draw included tokens (see Billing).
- The cost figure Claude Code displays is its own estimate and doesn't reflect MindsHub billing, especially on non-Claude aliases. Your usage summary is authoritative.
Anthropic SDKs
Install with pip install anthropic (Python) or npm install @anthropic-ai/sdk (TypeScript).
- Python
- TypeScript
import os
import anthropic
client = anthropic.Anthropic(
base_url="https://api.mindshub.ai",
auth_token=os.environ["MINDSHUB_API_KEY"], # auth_token, not api_key
)
message = client.messages.create(
model="sonnet",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello"}],
)
print(message.content[0].text)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic({
baseURL: "https://api.mindshub.ai",
authToken: process.env.MINDSHUB_API_KEY, // authToken, not apiKey
});
const message = await client.messages.create({
model: "sonnet",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
The anthropic-version header your SDK sends is accepted and ignored.
Model names
The model field accepts two forms:
- A MindsHub alias:
sonnet,opus,gpt,kimi, any alias from Models. This is how you run Claude Code on a non-Claude model. - A real Claude model name: anything starting with
claudethat contains a family name (opus,sonnet,haiku, orfable; a substring match, checked in that order) maps to the corresponding alias.claude-sonnet-5,claude-sonnet-4-6-20250929, andclaude-opus-5[1m]all work; version and date segments are ignored, and the family decides the alias. This is what lets Claude Code's own model picker work unmodified.
A claude… name with no recognizable family word returns 404 model_not_found; there is no silent guessing.
The response's model field echoes back exactly the string you sent (unlike /v1/chat/completions, which reports the resolved ID).
What's supported
- Text and multi-turn conversations;
systemas a string or content blocks. - Images (
imageblocks withbase64orurlsources). - Client tool use:
toolswithinput_schema,tool_use/tool_resultblocks round-trip,is_errorpreserved. tool_choice:auto,any,none, and{"type": "tool", "name": ...}.- Anthropic's hosted web tools:
web_search*andweb_fetch*tool types map onto the platform's web search where the target model supports it (see Chat completions → Built-in web search). - Prompt caching:
cache_controlbreakpoints are honored on Claude-family targets. Cache usage is reported in the response'susage. - Streaming (see below), and
POST /v1/messages/count_tokens.
What's not supported
These request features are accepted but ignored: the request succeeds and the feature silently doesn't happen (the same accepted-and-ignored rule as the OpenAI-compatible endpoints).
| Feature | Behavior |
|---|---|
thinking (extended thinking) | Ignored as a request control: thinking blocks in message history are stripped, and you can't set a budget. Models that think by default still return a thinking block in content (see the response-shape notes below); reasoning bills as output tokens either way. |
metadata | Ignored. |
Server tools (computer_*, bash_*, text_editor_*, code_execution, memory) | Dropped from the request. |
mcp_servers (server-side MCP) | Ignored. (Claude Code's own MCP support is client-side and unaffected.) |
Files API references ("source": {"type": "file"}) | Unsupported, and behavior is target-dependent: some providers reject them, others ignore them. Use base64 or url image sources. |
| Message Batches API | Not implemented. POST /v1/messages/batches returns a plain 404. |
| Citations / search-result blocks | Not returned. Web-search results reach you only as text the model wrote. |
Sampling parameters (temperature, top_p, top_k, stop_sequences) follow the same per-model policy as the OpenAI endpoints: forwarded where the target model accepts them, dropped and named in X-MindsHub-Dropped-Params where it doesn't. On the current Claude 5 models (opus, sonnet, fable) that means temperature, top_p, and top_k are dropped while stop_sequences work; haiku forwards everything. One quirk: a stop triggered by your sequence reports stop_reason: "end_turn", not stop_sequence, so the truncation is silent.
Unknown top-level request fields follow the same rule today: accepted and ignored, not a validation error. Unknown nested content, say an unrecognized block type inside messages, can be forwarded to the provider and fail there instead.
Response shape
{
"id": "msg_5084f82319564e568c6e82fd8520c125",
"type": "message",
"role": "assistant",
"model": "sonnet",
"content": [{"type": "text", "text": "Hello!"}],
"stop_reason": "end_turn",
"stop_sequence": null,
"usage": {
"input_tokens": 11,
"output_tokens": 4,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0
}
}
contentblocks aretext,tool_use, and, on models that think by default (opus,fable), a leadingthinkingblock, usually with empty or withheld content plus asignature. Don't assume the first block is your text.stop_reasonis one ofend_turn,tool_use,max_tokens,refusal.- All four
usagefields are always present. As in Anthropic's own API,input_tokensexcludes cached tokens: the three input fields partition the prompt.
Streaming
"stream": true produces the standard Anthropic event sequence:
event: message_start → event: ping → event: content_block_start
→ event: content_block_delta … → event: content_block_stop
→ event: message_delta → event: message_stop
Differences from Anthropic's native stream:
pingis sent once, right aftermessage_start, not periodically. Don't use pings as a liveness signal.- On non-Claude models,
message_startreportsinput_tokens: 0. The real counts arrive in the finalmessage_delta. Token-tracking UIs will undercount mid-stream on non-Claude models. - There is no
errorevent, and no reliable failure signal. A mid-generation failure can end the stream early withoutmessage_stop, but it can also surface as a normal-looking completion: an ordinarymessage_deltawithstop_reason: "end_turn"followed bymessage_stop, with truncated or empty content. If your application must detect failed generations, sanity-check the output; don't rely on the event sequence. - If the request fails before generation starts, you get a JSON error response (see below), not an SSE stream.
Counting tokens
curl https://api.mindshub.ai/v1/messages/count_tokens \
-H "Authorization: Bearer $MINDSHUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "sonnet", "messages": [{"role": "user", "content": "Hello"}]}'
{"input_tokens": 8}
Counts are estimates for every model: a single Claude tokenizer is used regardless of the model you pass, so counts are close for Claude-family targets and rougher for everything else. (Anthropic documents its own token counts as estimates too.) Budget with them; don't reconcile billing with them. count_tokens calls are free and unmetered.
Errors
Errors on this endpoint use the Anthropic envelope:
{"type": "error", "error": {"type": "not_found_error", "message": "The model 'foo' does not exist or you do not have access to it."}}
The status codes and their meanings are the same as everywhere else; see Errors. Three quirks specific to this endpoint:
- A 402 (empty wallet) arrives typed
invalid_request_error, and a 503 typedapi_error. Read the HTTP status, not just the type string. - On errors, none of the
X-MindsHub-*denial headers orRetry-Afterare currently sent on this endpoint (a fix is rolling out). Back off on any 429 without waiting for a hint. This applies to error responses only; the param-adaptation headers are reported normally on successful requests. - A malformed request body returns
400(message prefixedInvalid request body:), not the422the OpenAI-compatible endpoints use.
Behavior on this page verified against the platform in July 2026.