Messages API
Send Messages requests to https://api.katara.com/v1/messages, with your Katara key in x-api-key or
Authorization: Bearer. If you send both, they must carry the same key. The
anthropic-version header is optional; 2023-06-01 and 2026-10-21 are accepted, any other
value is refused.
curl 'https://api.katara.com/v1/messages' \ -H "x-api-key: $KATARA_API_KEY" \ -H 'anthropic-version: 2023-06-01' \ -H 'Content-Type: application/json' \ -d '{ "model": "katara/cortex", "max_tokens": 2048, "messages": [{"role": "user", "content": "Explain this project layout."}] }'An Anthropic SDK takes the address without /v1: Anthropic(base_url="https://api.katara.com", api_key=...).
Claude Code runs against Katara with ANTHROPIC_BASE_URL=https://api.katara.com and your key in
ANTHROPIC_API_KEY; edits, client tools and MCP servers, resumed sessions, prompt caching and
web search all work.
Messages uses the same account, payment method and Katara Community setting as Chat Completions. A request never switches payment methods. Payment challenges and receipt headers reach wallet clients unchanged.
Model names
Section titled “Model names”Any model is accepted, including the Claude names Anthropic clients send by default, and
Katara Cortex serves it (Model names in requests).
The reply’s model is katara/cortex. A request paid with x402
may name katara/cortex-genius or katara/cortex-smart to fix the model; its reply still names
katara/cortex, and a key that names either is refused. GET /v1/models with an anthropic-version header,
and GET /v1/models/{id}, answer in the Anthropic shape with that one model.
Content
Section titled “Content”system takes a string or text blocks. A message’s content takes:
- text;
- images (
image/jpeg,image/png,image/gif,image/webp) as base64, anhttpsurl, or afilesource naming afile_iduploaded through/v1/files; - documents: a base64 PDF, plain
text,contentblocks, or afile_id, each with an optional title and context. A document given byurlis refused, because Katara does not fetch it; search_resultblocks;- assistant
tool_useandthinkingblocks, and usertool_resultblocks.
A request ending on an assistant message (prefill) is refused. max_tokens: 0 answers an
empty message with stop_reason: "max_tokens" and an input estimate in usage, without
running a model or charging anything.
Each tool has a name of up to 128 letters, digits, _ or -, an object input_schema, and
optionally description, strict, input_examples, eager_input_streaming,
allowed_callers and cache_control. defer_loading: true is refused. tool_choice takes
auto, none, any, or tool with a declared name; disable_parallel_tool_use: true gets
at most one call per reply. A forced choice that the model ignores is not delivered: Cortex
tries the next model.
Return each tool’s id unchanged. All results belong at the start of the next user message,
before any text; duplicate, missing and unknown ids are refused. A result can carry text,
images, documents and search results. An error result reaches the model with
is_error: true and its text.
Anthropic’s versioned client tools become ordinary tools with their published names and
schemas, so your client runs them as it would anyway: bash_20241022 and bash_20250124,
the text_editor_ tools from 20241022 to 20250728, and memory_20250818.
Server tools that Katara does not run are refused with a message naming the feature: web
fetch, code execution, computer use, browser control, tool search, the advisor and the MCP
connector (mcp_toolset tools, or a non-empty mcp_servers). A top-level container is
refused too. Run an MCP server in your client and declare its tools in tools.
Web search
Section titled “Web search”Declare a web_search_ tool (web_search_20250305, web_search_20260209 or
web_search_20260318, named web_search) and Katara runs the searches the model asks for.
max_uses lowers the cap of five searches per request, allowed_domains or
blocked_domains (not both) narrows the results, and user_location is accepted. Each
search the model makes appears as a server_tool_use block followed by a
web_search_tool_result block before the text that uses it. In a stream the server_tool_use
block opens when the search starts, and its result follows once the search has run. A failed search comes back as a result with an error code (invalid_tool_input,
query_too_long, too_many_requests, max_uses_exceeded or unavailable); the model
answers without it and the search is not charged. Once the model asks to search, the rest of the request is served by
Katara’s managed models only. If it then ends without an answer, the searches and the model calls
after the first are not charged.
Web search has the price and when it is offered.
Send earlier server_tool_use and web_search_tool_result blocks back unchanged in
assistant history; they keep the page text the model read.
Thinking and caching
Section titled “Thinking and caching”thinking, output_config.effort and task_budget are accepted in every form, budgets
included, and change nothing: Katara Cortex decides how much the model reasons. Reasoning
arrives as thinking blocks with an empty signature. Send thinking blocks back as you
received them; thinking with another service’s signature is read as plain reasoning, and
redacted_thinking is dropped.
cache_control on the system prompt, tools, messages or the request (ttl 5m or 1h) is
served by Katara’s own prompt caching. context_management
(clear_tool_uses_20250919, clear_thinking_20251015, compact_20260112) and a top-level
compaction are served by Katara’s context management.
output_config.format and output_format with a JSON schema ask for structured output. Any
anthropic-beta header is accepted. temperature and top_p take 0 to 1. metadata.user_id, top_k, service_tier, speed,
inference_geo, diagnostics, fallbacks and fallback_credit_token are accepted and not sent
to a model. thread is refused: send the whole conversation in messages. Other unknown fields
are refused with a clear error.
Keep katara.session from the last successful reply and send it back on the next request
for that conversation. katara.reset_session: true starts a new session. A session token
does not replace authentication or authorize payment.
Stop sequences
Section titled “Stop sequences”stop_sequences takes any number of strings. Katara applies them itself: the reply ends
before the first match and nothing after it is sent. stop_reason is then stop_sequence and
stop_sequence holds the matched string. Text the model wrote past the match is still paid
for.
Streaming and usage
Section titled “Streaming and usage”Set stream: true for named server-sent events. The sequence starts with message_start;
each content block has a start, deltas and a stop. Tool arguments arrive as
input_json_delta fragments; accumulate them by block index and parse the JSON when that
block stops. A reply that has not begun after ten seconds starts its stream early, and a
ping follows every ten seconds of silence, so a client that waits on a long first token
does not time out. Streams paid with x402 never start early, so their payment headers come
first.
The final message_delta carries the authoritative usage, followed by message_stop.
input_tokens excludes cached input: add cache_read_input_tokens and
cache_creation_input_tokens to obtain total input. server_tool_use.web_search_requests
counts the charged searches. The final delta, and a non-streamed reply beside usage, also
carry the katara object with the charge; read the decimal cost_usd or cost_usdc as a
string (Usage and cost).
stop_reason is end_turn, max_tokens, tool_use, stop_sequence or refusal (with
stop_details).
An interrupted stream emits an error event without message_stop. Wait for
message_stop before treating the turn as complete, and check your usage before retrying an
interrupted request.
Errors
Section titled “Errors”Errors use the Anthropic envelope, with request_id in the body and a request-id header on
every reply.
| HTTP | error.type | When |
|---|---|---|
| 400 | invalid_request_error | The body is malformed or uses a refused feature. Not retried (x-should-retry: false). |
| 401 | authentication_error | Missing or unknown key. |
| 402 | billing_error | The funds behind the key cannot cover the request. Not retried. |
| 403 | permission_error | The account or the key’s environment refuses the request, for example a suspended account or Katara Community turned off. |
| 404 | not_found_error | No API route at that path. |
| 413 | request_too_large | The body is over 32 MB. |
| 429 | rate_limit_error | Every vendor that could serve the request is rate limiting. Retry-After says when to retry. |
| 500 | api_error | Something failed behind Katara. |
| 529 | overloaded_error | No candidate could serve the request in time. Retry-After says when to retry. |
/v1/messages/batches and its sub-paths answer 400 invalid_request_error: Katara does not
run message batches. Send each request to /v1/messages.
Token counting
Section titled “Token counting”POST https://api.katara.com/v1/messages/count_tokens takes the same body as /v1/messages and returns an
estimate of its input. It needs a key, never runs a model and never reserves payment.
Generation controls such as max_tokens are accepted and ignored.
{"input_tokens": 293, "katara": {"estimated": true, "estimation_method": "conservative-v2", "bytes_per_token": 3}}Use it for context management, never to predict a bill. Text, tool calls and tool definitions count one token per three bytes, plus 16 for the request, 4 per message and 16 per tool definition. Each image counts 2,240 tokens, each PDF page 1,120 and a stored file 4,480. The estimate runs above the real count, so a client compacts a little early rather than overflowing. Billed usage comes only from inference.