Skip to content

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.

Terminal window
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.

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.

system takes a string or text blocks. A message’s content takes:

  • text;
  • images (image/jpeg, image/png, image/gif, image/webp) as base64, an https url, or a file source naming a file_id uploaded through /v1/files;
  • documents: a base64 PDF, plain text, content blocks, or a file_id, each with an optional title and context. A document given by url is refused, because Katara does not fetch it;
  • search_result blocks;
  • assistant tool_use and thinking blocks, and user tool_result blocks.

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.

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, 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 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.

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 use the Anthropic envelope, with request_id in the body and a request-id header on every reply.

HTTPerror.typeWhen
400invalid_request_errorThe body is malformed or uses a refused feature. Not retried (x-should-retry: false).
401authentication_errorMissing or unknown key.
402billing_errorThe funds behind the key cannot cover the request. Not retried.
403permission_errorThe account or the key’s environment refuses the request, for example a suspended account or Katara Community turned off.
404not_found_errorNo API route at that path.
413request_too_largeThe body is over 32 MB.
429rate_limit_errorEvery vendor that could serve the request is rate limiting. Retry-After says when to retry.
500api_errorSomething failed behind Katara.
529overloaded_errorNo 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.

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.