Reasoning
Some models produce a reasoning trace (reasoning or extended thinking) before the final answer. kenari forwards that trace as-is and bills its tokens as normal output tokens. This page explains how to request reasoning and where to read it in the response.
Models that support reasoning
Section titled “Models that support reasoning”In GET /v1/models, models that support reasoning have the reasoning: true flag. When available, the model also includes reasoning_options, a list of effort levels you can choose (for example low, medium, high). Reasoning model ids are in the catalog: look for models with the reasoning flag. See Models & pricing.
Request reasoning
Section titled “Request reasoning”How you request it depends on the endpoint style you use.
In /v1/chat/completions, use the reasoning_effort field (for example "medium") for models that have reasoning_options.
curl https://kenari.id/v1/chat/completions -H "Authorization: Bearer kn-..." -H "Content-Type: application/json" -d '{"model":"<model with the reasoning flag>","reasoning_effort":"medium","messages":[{"role":"user","content":"Hitung 17 * 24 dan jelaskan langkahnya."}]}'Reasoning model ids are in the catalog, marked with the reasoning flag in GET /v1/models. Replace the model placeholder above with one of those ids.
In /v1/messages, use the Anthropic-style thinking field.
{ "model": "step-3-7-flash", "max_tokens": 1024, "thinking": { "type": "enabled", "budget_tokens": 512 }, "messages": [ { "role": "user", "content": "Hitung 17 * 24 dan jelaskan langkahnya." } ]}Unified reasoning controls (the reasoning object)
Section titled “Unified reasoning controls (the reasoning object)”Besides reasoning_effort (flat string) and the thinking block in /v1/messages, kenari also accepts an OpenRouter-style reasoning object directly in the /v1/chat/completions body. This object gives more detailed and more consistent control across providers.
| Field | Type | Description |
|---|---|---|
effort | string | Effort level: low, medium, high, xhigh, or max. Mapped to reasoning_effort (OpenAI/DeepSeek backends) or budget_tokens (Anthropic backends). |
enabled | boolean | false turns off reasoning (translated to each backend’s native method: GLM thinking: {type: "disabled"}, Qwen chat_template_kwargs, OpenAI/DeepSeek reasoning_effort: "none", Anthropic omits the thinking block). true without effort/max_tokens turns reasoning on at medium level, so backends where the default is off (for example Anthropic) still think. |
max_tokens | integer | Reasoning token limit. Mapped to budget_tokens (Anthropic, as part of the request’s max_tokens according to the effort level) or the nearest effort level (OpenAI). |
exclude | boolean | true hides reasoning trace text from the response. Tokens are still generated and billed as output. Only the text is not returned. |
If both reasoning and reasoning_effort are present in one request, the reasoning object takes effect.
Example: turn off reasoning
curl https://kenari.id/v1/chat/completions -H "Authorization: Bearer kn-..." -H "Content-Type: application/json" -d '{"model":"<model with the reasoning flag>","reasoning":{"enabled":false},"messages":[{"role":"user","content":"Jawab singkat: ibu kota Indonesia?"}]}'kenari translates enabled: false to the active backend’s native parameter, so your code does not need to know how each provider turns off reasoning.
Reading reasoning traces
Section titled “Reading reasoning traces”In /v1/chat/completions responses, reasoning text appears in choices[].message.reasoning. The same field is also included as reasoning_content for compatibility with tools that read that field.
{ "choices": [ { "message": { "role": "assistant", "reasoning": "17 * 24 = 17 * 20 + 17 * 4 ...", "reasoning_content": "17 * 24 = 17 * 20 + 17 * 4 ...", "content": "Hasilnya 408." } } ]}In /v1/messages, the thinking block is forwarded inside content in the Anthropic format, separate from the answer text block.
{ "content": [ { "type": "thinking", "thinking": "17 * 24 = 408 ..." }, { "type": "text", "text": "Hasilnya 408." } ]}Billing reasoning tokens
Section titled “Billing reasoning tokens”Reasoning tokens are still counted as output and billed at the normal output rate, like answer tokens. Choosing a higher effort level (or a larger budget_tokens) means more output tokens, so the cost rises. See Billing.
Small max_tokens and empty output
Section titled “Small max_tokens and empty output”Reasoning models spend part of max_tokens on thinking before writing an answer. If max_tokens is set too small, the whole budget can be consumed by reasoning before a single answer token comes out. The result is an empty response, but kenari flags it honestly instead of making it look like the model stopped on its own:
/v1/chat/completions:finish_reasonbecomes"length"./v1/messages:stop_reasonbecomes"max_tokens"./v1/responses:statusbecomes"incomplete"withincomplete_details: {"reason": "max_output_tokens"}.
Reasoning tokens already spent are still billed as usual. A used-up budget does not mean a free turn. For models with the reasoning flag, set max_tokens to at least 512 so there is room for an answer after reasoning finishes.