Responses
POST https://api.katara.com/v1/responses takes the OpenAI Responses request shape and is served by Katara
Cortex. Routing, payment and charges follow the same rules as
Chat Completions; a request with a key is paid with that key, one without a key
per request with x402. The OpenAI SDKs and the Vercel AI
SDK work against it with https://api.katara.com/v1 as the base URL.
curl 'https://api.katara.com/v1/responses' \ -H "Authorization: Bearer $KATARA_API_KEY" \ -H 'Content-Type: application/json' \ -d '{ "model": "katara/cortex", "input": "Explain a Merkle tree in two sentences.", "max_output_tokens": 200 }'Read assistant text from output items whose type is message, then from their content
parts whose type is output_text. A reply can also hold function calls, reasoning items and
web search calls.
Model names
Section titled “Model names”Any model is accepted, including the GPT names OpenAI 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.
input is a string or an array of typed items. Message roles are user, assistant,
system and developer. A message’s content is text or typed parts: input_text,
output_text and refusal; input_image by image_url or file_id; input_file by
file_id or file_data; and input_audio. Files are uploaded through
/v1/files. instructions is sent as a system message.
Function tools use a flat declaration:
{ "type": "function", "name": "read_file", "parameters": { "type": "object", "properties": { "path": { "type": "string" } }, "required": ["path"] }}A returned function_call carries call_id, name and arguments as JSON text. Run the tool
in your application, then send the call and its result in the next request, or send only the
result with previous_response_id:
[ {"type":"message","role":"user","content":"Read README.txt"}, {"type":"function_call","call_id":"call_1","name":"read_file","arguments":"{\"path\":\"README.txt\"}"}, {"type":"function_call_output","call_id":"call_1","output":"Project setup instructions"}]Each result must match an outstanding call. A function_call_output can be a string or a list
of parts, images and files included.
Besides function, Katara takes custom tools (freeform input, with a grammar described to
the model), namespace tools (one level deep), tool_search and web_search. tool_choice
takes auto, none, required, a named function or custom tool, and allowed_tools;
parallel_tool_calls: false gets at most one call per reply. Hosted tools Katara does not run
are refused with 400 unsupported_tool naming the tool: file_search, mcp, computer,
computer_use and computer_use_preview, code_interpreter, image_generation, local_shell, shell and
apply_patch.
Web search
Section titled “Web search”A web_search tool (web_search_preview and the dated variants too) lets the model search the
web through Katara. max_tool_calls lowers the cap of five searches per request, and
filters.allowed_domains or filters.blocked_domains narrows the results. Each search comes back as a web_search_call
item with its sources, and the answer’s output_text carries url_citation annotations for
the pages it quotes. In a stream the item opens with response.web_search_call.in_progress and
response.web_search_call.searching when the search starts, and ends with
response.web_search_call.completed once its results are in. 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. Search needs a key; Web search has the
price and when it is offered.
Reasoning and other fields
Section titled “Reasoning and other fields”reasoning (any effort, summary) is accepted and changes nothing: Katara Cortex decides how
much the model reasons. Reasoning comes back as reasoning items, with summary_text when you
asked for a summary. Reasoning items can be sent back in history. include values are
accepted; Katara returns no encrypted reasoning, and encrypted_content sent back is dropped.
text.format takes text, json_object or json_schema, and text.verbosity is accepted.
background: true is accepted and answered when the reply is complete. truncation,
metadata, user, safety_identifier, service_tier, stream_options, top_logprobs,
prompt_cache_retention, context_management, client_metadata and access_programs are
accepted.
prompt_cache_key keeps a conversation on the model whose cache holds its start
(Caching). A stored prompt template is refused. Any other field
is refused with 400 unsupported_parameter naming it.
Streaming and charges
Section titled “Streaming and charges”Set stream: true for server-sent events. Each event has a name, JSON data and a
sequence_number. The stream starts with response.created and response.in_progress. Text
arrives in response.output_text.delta, tool arguments in
response.function_call_arguments.delta and response.custom_tool_call_input.delta, and
reasoning in response.reasoning_text.delta or the summary events.
Wait for response.completed, response.incomplete or response.failed; a closed connection
is not enough to establish completion. An incomplete response names max_output_tokens or
content_filter in incomplete_details.reason. A failed stream’s error.code is one of the
codes in Errors.
The final response carries usage (input_tokens, with cached_tokens and
cache_write_tokens under input_tokens_details; output_tokens, with reasoning_tokens;
total_tokens) and the katara object with the charge. See Usage and cost.
Stored responses
Section titled “Stored responses”A response is stored unless the request sends store: false, and is kept 30 days from when it
was created, then deleted. Reading or continuing it does not extend that. Stored responses
are kept in their own store, apart from ordinary logs.
- With a key, a response belongs to the key’s account, and only keys of that account can read, continue or delete it.
- Without a key, a response belongs to nobody: no account or payer address is kept with it, and whoever holds its id can read, continue or delete it. Treat the id as a secret.
The routes:
previous_response_idcontinues from a stored response: its input and output become the start of the new request.conversation(an id, or{"id": ...}) continues from the latest stored response in that conversation. It needs a key.GET /v1/responses/{response_id}returns a stored response.?stream=trueis refused.GET /v1/responses/{response_id}/input_itemslists its input items, newest first, or oldest first withorder=asc.DELETE /v1/responses/{response_id}deletes it and answers{"object": "response.deleted"}.POST /v1/responses/{response_id}/cancelanswers400 response_not_cancellable: every response has finished by the time it is answered.
A response that is missing, expired, deleted or someone else’s is 404 response_not_found; as
previous_response_id it is 404 previous_response_not_found. If saving a response fails, the
reply is still delivered; only the continuation is lost.
Errors
Section titled “Errors”Format errors are 400 with param naming the field: invalid_json, invalid_type,
invalid_value, unsupported_parameter, unsupported_tool, and invalid_request for a
malformed or oversized body. Payment and capacity errors are those of
Chat Completions, passed through unchanged: 402 insufficient_quota
when the funds cannot cover the request, 429 provider_rate_limited, 500 when every
candidate’s reply failed or was refused, and 503 with Retry-After.