Create a chat completion
const url = 'https://api.katara.com/v1/chat/completions';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"model":"katara/cortex","messages":[{"role":"user","content":"Explain a Merkle tree in two sentences."}],"max_tokens":200}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.katara.com/v1/chat/completions \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "model": "katara/cortex", "messages": [ { "role": "user", "content": "Explain a Merkle tree in two sentences." } ], "max_tokens": 200 }'Same request body as OpenAI chat completions. Set stream: true for server-sent events.
Any model name is accepted and served by Katara Cortex; the reply names katara/cortex.
Without a key the request may instead name katara/cortex-genius or katara/cortex-smart,
which fix the model and which the reply names; with a key those two are refused with
model_requires_x402. The reply carries a katara object with what you were charged. Top-level
katara_web_search, or OpenAI’s web_search_options, lets the model search the web
(Web search).
Stop sequences are applied by Katara: the reply ends before the first match.
In a stream it arrives as one final chunk with an empty choices array, after the content
and before data: [DONE].
Admission is checked before any work starts: the balance behind the key must cover the
maximum this request could cost (input estimate plus max_tokens at the offer price).
Otherwise the request is refused with 402 insufficient_quota and nothing is charged.
Fields current OpenAI clients send that change nothing a Katara reply can contain
(metadata, store, service_tier, safety_identifier, verbosity, moderation,
prediction, prompt_cache_options, prompt_cache_retention, modalities: ["text"])
are accepted and dropped, as is user, which never reaches a provider. seed reaches a
model that reads it. prompt_cache_key keeps a conversation on the model holding its
prompt in cache.
Without a key the request is paid with x402: the answer is 402 with a quote in the
PAYMENT-REQUIRED header, and the same body sent again with a signed payment for one of
the quote’s entries in PAYMENT-SIGNATURE is served and settled on the Live network.
Pay per request with x402 describes the exchange.
Authorizations
Section titled “Authorizations”- bearerAuth
- None
Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Without a key, base64 of the x402 payment payload that signs the quote from a previous 402.
The same payload under the header name of the first x402 version, paid with exact.
Request Bodyrequired
Section titled “Request Bodyrequired”object
object
object
object
object
A base64 data URL (PNG, JPEG, WebP, GIF, HEIC or HEIF) or an https URL.
object
object
The recording, base64.
A PDF or a video, sent inline. To name a file uploaded with POST /files, use a FileIDPart.
object
object
A base64 data URL with the file’s type: application/pdf (up to 1,000 pages), or
video/mp4, video/mpeg, video/quicktime, video/webm, video/x-msvideo,
video/x-flv, video/x-ms-wmv or video/3gpp.
A file uploaded with POST /files, named by its id.
object
object
Bounds the output and therefore the maximum charge.
Lowered to a model’s own cap when it is above it.
Function tools, and custom tools that take one string of input. Names up to 128 characters.
object
False gets at most one tool call per reply.
object
Applied by Katara; the reply ends before the first match.
Lets the model search the web, at most five times per request, each successful search charged 0.006 USDC or credits; a request that ends without an answer is charged nothing for its searches or the model calls after the first search, which run on managed models only. The first call routes as any request does, Katara Community included, and stays charged when Katara Community served it. Not offered without a key, on the Test network, on a marketplace-only key, or with tool_choice none or a named function.
object
Not with allowed_domains.
object
OpenAI’s web search option. It turns on katara_web_search with its user_location.approximate; katara_web_search wins when both are sent.
object
Read by Katara and removed before the request reaches any model.
object
Opaque routing token from the last served reply; it grants no payment authority.
Start a new routing session explicitly.
A short step summary, limited to 80 words by Katara Cortex.
When the request’s input passes trigger_tokens, Katara has a fast model
summarise every turn before the last keep_turns, sends the model the summary in
their place, and returns it as katara.compaction in the reply. Send that summary
instead of those turns from then on. The summary is billed to you as its own request
and shown in katara.compaction.summary. Not offered without an API key.
object
Once the request’s tool results add up to trigger_tokens, results from turns at
least keep_turns old are replaced with a one-line note before the model sees them.
The cleared span grows keep_turns turns at a time, so the start of the conversation
stays the same between steps. The reply’s katara.context_edits says what was cleared.
object
Keep the start of the request in an explicit cache, for a model
that offers one (the Standard and Light models). The tools and the first
messages messages are cached; 0, the default, caches the leading system messages.
The request that writes a cache pays to keep it for ttl_seconds; later requests
with the same start read it at the cached input rate. Ignored on account credits and
by models without explicit caching.
object
Example
{ "model": "katara/cortex", "messages": [ { "role": "user", "content": "Explain a Merkle tree in two sentences." } ], "max_tokens": 200}Responses
Section titled “Responses”The completion, or a server-sent event stream when stream is true.
object
katara-cortex on every reply.
object
object
Null when the reply is tool calls only.
Validated calls. Every entry has an id, a non-empty name and arguments that parse as a JSON object.
object
object
A JSON object document.
object
Present when the vendor read part of the prompt from its cache.
object
Prompt tokens billed at the cached input rate.
What this reply cost.
object
The settled price, in USDC, as a decimal string. For a request paid with x402 it is the charge, the model’s minimum included (0.025 USDC, 0.05 for katara/cortex-genius, 0.01 for katara/cortex-smart).
The Credits charge as a decimal string. This legacy field name is retained for compatibility; display Credits without a dollar sign.
On a request paid with x402, the payment that settles the reply.
object
The token paid.
The charge in the token’s base units, the same as amount in PAYMENT-RESPONSE.
The provider’s address, or managed when a vendor answered.
Prompt tokens the vendor read from its cache, billed at the cached input rate.
What the cached tokens saved against the input rate, in USDC.
The same saving in Credits, on a reply paid with account credits.
When katara.compaction summarised the conversation.
object
The system message to send in place of the summarised messages.
object
First index in this request’s messages that the summary replaces.
First index kept after it.
The summary request’s usage and its cost (cost_usdc or cost_usd).
object
Why no summary was made; the request went whole.
object
Tokens this request wrote to a new explicit cache (katara.cache).
How long that cache is kept.
What keeping it costs, in USDC; included in cost_usdc.
On Test, a reply with fixed text that no model wrote, served when no Test provider was free.
The stop sequence at which Katara ended the reply.
The searches this request was charged for.
object
The successful searches; only those are charged, and none when the request ended without an answer.
On a web search request, how many model calls it made.
Every search the model made, in order. Not on stream chunks, which carry each search as it runs.
object
object
On an image reply from a model that edits, the id to send as previous_edit_id.
What this reply cost.
object
The settled price, in USDC, as a decimal string. For a request paid with x402 it is the charge, the model’s minimum included (0.025 USDC, 0.05 for katara/cortex-genius, 0.01 for katara/cortex-smart).
The Credits charge as a decimal string. This legacy field name is retained for compatibility; display Credits without a dollar sign.
On a request paid with x402, the payment that settles the reply.
object
The token paid.
The charge in the token’s base units, the same as amount in PAYMENT-RESPONSE.
The provider’s address, or managed when a vendor answered.
Prompt tokens the vendor read from its cache, billed at the cached input rate.
What the cached tokens saved against the input rate, in USDC.
The same saving in Credits, on a reply paid with account credits.
When katara.compaction summarised the conversation.
object
The system message to send in place of the summarised messages.
object
First index in this request’s messages that the summary replaces.
First index kept after it.
The summary request’s usage and its cost (cost_usdc or cost_usd).
object
Why no summary was made; the request went whole.
object
Tokens this request wrote to a new explicit cache (katara.cache).
How long that cache is kept.
What keeping it costs, in USDC; included in cost_usdc.
On Test, a reply with fixed text that no model wrote, served when no Test provider was free.
The stop sequence at which Katara ended the reply.
The searches this request was charged for.
object
The successful searches; only those are charged, and none when the request ended without an answer.
On a web search request, how many model calls it made.
Every search the model made, in order. Not on stream chunks, which carry each search as it runs.
object
object
On an image reply from a model that edits, the id to send as previous_edit_id.
Example
{ "id": "chatcmpl-7f3a9c2e1b0d", "object": "chat.completion", "model": "katara/cortex", "system_fingerprint": "katara-cortex", "choices": [ { "index": 0, "finish_reason": "stop", "message": { "role": "assistant", "content": "A Merkle tree hashes data in pairs up to one root hash…" } } ], "usage": { "prompt_tokens": 18, "completion_tokens": 52, "total_tokens": 70 }, "katara": { "cost_usdc": "0.000018", "provider": "0xfFe5…38DC" }}data: {chunk} lines ending with data: [DONE]: a role chunk, content deltas, each
tool call whole in one chunk, a finish chunk, a chunk with empty choices carrying
usage, then one carrying katara. A web search request adds a chunk with empty
choices and katara_web_search_call (id, query) as each search starts, and
one with katara_web_search (the search and its results) once it has run. A failure after content was sent ends with an
error chunk (stream_interrupted or provider_output_invalid) before [DONE].
Headers
Section titled “Headers”Request id for support and for matching usage records.
On a request paid with x402, base64 of { success, payer, transaction, network, amount }.
amount is the charge in the token’s base units, equal to katara.payment.amount, and is
absent on a stream, whose headers are sent before the cost is known; the stream’s final
chunk carries it. transaction is empty: settlement is submitted after the reply.
X-PAYMENT-RESPONSE carries the same value.
Malformed request, something no candidate can serve (feature_not_supported, with
param naming the field), a request longer than every candidate’s window
(context_length_exceeded), a malformed katara_web_search (invalid_web_search) or
custom tool (invalid_value), or a model that a key paid with account credits cannot
use (model_requires_usdc), or katara/cortex-genius or katara/cortex-smart sent with a
key (model_requires_x402). A media part of the wrong shape, an audio format or file
type not listed, a PDF over 1,000 pages, or a file_id without a key is
invalid_request.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}Missing or unknown key (invalid_api_key).
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}The key pays with account credits and the available credits cannot cover this request
(insufficient_credits), or it pays with USDC and its spendable balance cannot
(insufficient_quota, with spendable_usdc and max_charge_usdc). Both are sent with
x-should-retry: false so SDKs do not retry them. Add credits or USDC, or raise the
budget cap, then retry.
Without a key, a quote: PAYMENT-REQUIRED holds base64 of a PaymentRequired object and
the body is the same object. Sign it and send the same body again. When the quoted model
fails before delivering, the request moves to the next model under the same payment. A
402 that answers a paid request with a quote is a new one: no model the signed amount
covered answered and a dearer one is left, or the authorization had too little validity
left. A payment that does not verify is refused with
payment_invalid and no PAYMENT-REQUIRED header.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
An x402 quote for one request.
object
The ways this request can be paid, for the same maximum. upto entries, where offered, come before exact. Sign one.
object
upto: a Permit2 transfer of at most amount, of which only the charge is pulled. exact: an EIP-3009 transfer of amount, with the difference refunded. Neither collects more than was signed.
The chain as a CAIP-2 id.
The USDC contract the authorization is for.
The most this request can cost, in the token’s base units. At least the model’s minimum: 25000 (0.025 USDC), 50000 for katara/cortex-genius, 10000 for katara/cortex-smart.
The settlement contract; the authorization’s to.
Validity to give the authorization.
object
The token’s EIP-712 domain name.
The token’s EIP-712 domain version.
exact only. The job this quote is bound to. It may be signed as the authorization nonce; a random nonce also works.
The job this quote is bound to.
upto only.
upto only. The address that settles; the signed witness names it.
The address paid for the reply.
The model paid for: katara/cortex-genius or katara/cortex-smart when the request named one, otherwise katara/cortex for a chat, Messages, Responses or image request; the embedding model for embeddings.
katara/cortex for a chat, Messages, Responses or image request, whatever it named; the embedding model for embeddings.
True when a vendor’s model will answer.
eip2612GasSponsoring, when present: the token takes EIP-2612 permits, and a permit for
Permit2 sent with an upto payment is submitted with the settlement at Katara’s cost.
object
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}Headers
Section titled “Headers”Base64 of the PaymentRequired object in the body. Present only on a quote.
The account is suspended (account_suspended), credit billing is paused for it (billing_suspended), only Katara Community could serve the request and it is turned off (community_off), or a Live key was sent to the Test network’s address under /test/ (wrong_environment).
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}An x402 payment with upto from a wallet that has not approved Permit2 for the token and carries no permit (permit2_allowance_required). The quote stays valid; approve once, or pay it with exact.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}More than 20 MB of media in one request, counted after base64 decoding
(media_too_large), or a body over 32 MB (request_too_large). A request without a key
is limited to a 4 MB body in all.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}Every vendor that could serve the request is rate limiting it (provider_rate_limited).
Nothing was charged; Retry-After repeats the vendor’s wait, up to 60 seconds.
Without a key, too many unpaid quotes from one address (quote_rate_limited): each may
ask for 10 at once and 30 a minute after that, and hold 16 open. Retry after Retry-After.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}Headers
Section titled “Headers”Every provider tried answered with something the marketplace refused to deliver, such as a malformed tool call (provider_output_invalid), every provider refused the request body itself (provider_rejected_request, sent with an x-should-retry header of false), or a provider failed before answering a request that could not move to another (provider_failed). A web search request whose model searched and wrote no answer also ends with provider_output_invalid, its katara object listing the searches. Nothing was charged, except a first call that Katara Community served before the search began. Retry after Retry-After. The API never answers 502 or 504.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}Headers
Section titled “Headers”Every vendor that could serve the request is overloaded (provider_overloaded), no provider can take it right now (no_capacity), no candidate started its reply in time (upstream_timeout), USDC is still being moved into the prepaid balance (funding_pending), or a Test key’s request did not reach the Test network (test_network_unavailable). On Test, a Cortex request with no free Test provider gets a simulated reply instead. Retry after Retry-After.
object
object
For people. Wording may change.
Stable. Branch on this. Errors says what each code means and what to do; new codes may be added.
The response’s x-katara-request-id.
Example
{ "error": { "type": "invalid_request_error", "code": "invalid_api_key" }}