Reasoning
Models that think before they answer: how much they think, how to cap it, and where the thinking comes back.
Most chat models here reason: they write their thinking first, then the answer. You choose how hard they think, can cap how long, and get the thinking back beside the answer.
How hard to think
| Route | The control |
|---|---|
/v1/chat/completions |
reasoning.effort, or the shorthand reasoning_effort |
/v1/responses |
reasoning.effort |
/v1/messages |
output_config.effort, or thinking (below) |
Effort runs from minimal through low, medium, high, xhigh and max to ultra. Leave it out and the model decides. Each model lists the levels it takes on its page, and a level it does not take is a 400.
curl https://api.vultrinference.com/v1/chat/completions \
-H "Authorization: Bearer $VULTR_INFERENCE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4.1-flash",
"reasoning": {"effort": "low"},
"messages": [{"role": "user", "content": "Is 221 a prime number?"}]
}'import os
from openai import OpenAI
client = OpenAI(base_url="https://api.vultrinference.com/v1", api_key=os.environ["VULTR_INFERENCE_API_KEY"])
reply = client.chat.completions.create(
model="deepseek-v4.1-flash",
messages=[{"role": "user", "content": "Is 221 a prime number?"}],
# Not one of OpenAI's own fields, so the SDK sends it as extra body
extra_body={"reasoning": {"effort": "low"}},
)
message = reply.choices[0].message
print("thought:", getattr(message, "reasoning", None))
print("answer:", message.content)
print("reasoning tokens:", reply.usage.completion_tokens_details.reasoning_tokens)To turn thinking off, send effort none or "reasoning": {"enabled": false}. A few models think whatever you send.
A cap on thinking
A budget caps how many tokens the model may spend thinking. It must be below the cap on the whole answer.
| Route | The budget |
|---|---|
/v1/chat/completions, /v1/responses |
reasoning.max_tokens |
/v1/messages |
thinking: {"type": "enabled", "budget_tokens": n}, at least 1,024 |
Not every model can hold to a budget; those that can say supports_max_tokens in their catalog entry. The others ignore it on chat completions and responses, and refuse it with a 400 on messages. On messages, thinking: {"type": "adaptive"} leaves the amount to the model.
Where the thinking comes back
| Route | The thinking | Its tokens |
|---|---|---|
/v1/chat/completions |
message.reasoning |
usage. |
/v1/responses |
a reasoning output item |
usage. |
/v1/messages |
a thinking block |
On chat completions it is always reasoning, whichever engine serves the model, and delta.reasoning in a stream. SDKs and compatibility shows a whole answer.
On messages, each thinking block comes with a signature. Send the block back on the next turn and the model sees its earlier thinking. With display: "omitted" the block arrives with empty text, but still with its signature.
Billing
Thinking tokens are output tokens: completion_tokens already includes them, and they are billed at the model's output price.
Endpoints