API Reference

Reasoning Models

Some models on the Draven AI platform "think" before answering — spending extra output tokens on an internal reasoning pass before writing the final reply. Whether a model does this at all, and whether you can tune how much it reasons, is a per-model capability — never assume it from one model to the next.

Reasoning support is not uniform across the catalog. There is no model on this platform for which it is safe to hardcode a fixed set of effort levels. A given model can (a) not reason at all, (b) reason but with no way to tune the effort, or (c) reason with a configurable effort — and even within (c), the accepted values differ from model to model. Always resolve this from GET /v1/models at runtime (see Checking support below) instead of assuming any model behaves like another.

How it works

Draven AI's API is a single, OpenAI-compatible surface in front of many different underlying models. Reasoning is not something Draven AI adds uniformly on top of every model — it's a capability each model either has or doesn't, implemented however that model's own architecture implements it. The API normalizes the request and response shape (the same thinking / reasoning_effort fields, the same message format, regardless of which model you call) but it cannot normalize what a model is technically capable of doing with its own reasoning process. That's why support fragments into distinct tiers instead of one universal on/off switch.

Concretely: a reasoning pass consumes output tokens before the visible reply is written, which is the mechanism behind the general trade-off — more reasoning tends to mean a slower, more expensive, but more carefully worked-through answer. Exactly how much slower or more expensive is model-specific and not something this page quotes numbers for, since it varies request to request.

Three tiers of support

Every chat model on the platform falls into exactly one of these three tiers. Knowing which tier a model is in tells you which of the two request fields (thinking, reasoning_effort) actually do something for it.

TierCan it reason?thinking (on/off)reasoning_effort (level)
1. Thinking + effort controlYesRespected (behavior described below)Respected, within that model's own accepted set
2. Thinking, fixed effortYesMay be respected, may be ignored — provider-dependentHas no effect; the model reasons at its own internal default regardless of what you send
3. No reasoning supportNoSilently ignored, no effect, no errorSilently ignored, no effect, no error

Two things worth being explicit about, since they're easy to get wrong:

Checking support before you rely on it

The public, unauthenticated GET /v1/models endpoint (see Models) returns every model with two booleans you should check before sending either reasoning field:

FieldTypeMeaning
thinkingbooleantrue if the model reasons at all (tier 1 or tier 2). false means tier 3 — the model never reasons, and the two request fields below have nothing to act on.
effort_controlbooleantrue only for tier 1: this model accepts reasoning_effort and will actually vary its behavior by level. false alongside thinking: true means tier 2. false alongside thinking: false means tier 3.

These two booleans are the only reliable, always-current source for which tier a model is in — the catalog changes over time, so resolve this at runtime rather than hardcoding a list of model ids per tier.

The model list does not publish the exact set of effort strings a tier-1 model accepts (e.g. whether it goes up to high or further). If you send a level a model doesn't recognize, the request still succeeds — see how unsupported levels are handled below — so building against effort_control plus the clamping behavior is safe even without that finer-grained list.

The thinking field

This field is the on/off switch for reasoning, independent of how much reasoning happens. It accepts three equivalent shapes, kept for compatibility with different client conventions:

FormExample
Boolean"thinking": false
Object with enabled"thinking": { "enabled": false }
Object with type"thinking": { "type": "disabled" }

If omitted, reasoning is enabled by default for any model that supports it (tier 1 or tier 2) — you have to explicitly opt out, not opt in.

Turning reasoning off is not guaranteed to behave the same way across models. This is the single most important nuance on this page. Depending on the model, thinking: false resolves to one of three different behaviors server-side, and which one applies is not something the client controls or is told:

  1. A genuine off. Some models have a real "off" state and stop reasoning entirely when asked.
  2. A step below the model's normal floor. Some models don't have a real off switch, but the provider serving them does recognize a special, even-lighter effort level than the lowest step of the ordinary lowmax scale (an internal value, not one you can request directly via reasoning_effort — it's only ever reached by sending thinking: false to one of these specific models). It's the closest thing to "off" that model's provider understands, but it isn't literally zero reasoning.
  3. The model's normal lowest effort step, unchanged. The rest of the models with no real off switch and no special lighter-than-low level just keep reasoning at whatever their lowest ordinary step is — from the outside, indistinguishable from never having sent thinking: false at all.

This is a real limitation of specific models' own APIs, not a bug in how the request is relayed — there is nothing on the client side that forces a model to do something its own inference stack doesn't support. If a request needs to guarantee no reasoning tokens are spent, don't rely on thinking: false against a tier-1 or tier-2 model; pick a model where thinking is false in the model list (tier 3) instead.

The reasoning_effort field

This field controls how much a tier-1 model reasons — it does nothing on tiers 2 or 3. It's a string. The platform's core ordered scale, from least to most reasoning, is lowmax below; minimal is included in the table to show where it sits relative to that scale, but read the note under the table before relying on it.

ValuePositionGeneral trade-off
minimalBelow lowNot part of the five-step scale itself — only usable directly on the specific models whose provider recognizes this exact wire value (see the callout below). On every other model it's clamped down to that model's own low (or whatever its floor is).
lowLowestFastest and cheapest reasoning pass.
mediumThe default used when reasoning_effort is omitted.
highMore thorough, at added latency and token cost.
extraBeyond high, on models that go this far.
maxHighestThe deepest reasoning pass any model on the platform exposes.

No model is guaranteed to accept the full five-step scale (lowmax). A given tier-1 model might only recognize two adjacent values from that list (say, its own "on" and "off" ends of the range), three, or all five — that's an attribute of the individual model, not something this page can enumerate generically. What's guaranteed platform-wide is that the accepted values are always drawn from this ordered list, in this order. minimal is shown in the table above to make its position clear, but it isn't part of that guaranteed five-step set — see the callout right below for exactly which models take it as-is.

"none" and "minimal" are both accepted as direct reasoning_effort values, but they sit outside the five-step lowmax scale above, and they don't mean the same thing:

"minimal" asks for the least possible reasoning while leaving reasoning turned on — on the specific models whose provider recognizes that exact wire value (a small, model-specific subset), it's honored as-is, sitting one step below that model's own low. On every other tier-1 model it's not silently treated as "off"; it's clamped like any unsupported level (see below) down to that model's own floor, and the model still reasons at that floor level.

"none" asks to turn reasoning off — it's handled exactly like sending thinking: false (see the thinking field above), including the same three possible outcomes depending on the model (a genuine off, a step below the model's normal floor, or no visible change on models with no real off switch). Sending both thinking: false and reasoning_effort: "none" is redundant, not contradictory — either one alone is enough.

Because they mean different things, sending "minimal" to a model that has a genuine off switch (see behavior 1 under thinking) does not turn reasoning off on that model — it only lowers the effort to that model's floor. Use "none" or thinking: false if you specifically want reasoning off.

What happens if you request a level a model doesn't support

The request is never rejected for an unsupported or unrecognized reasoning_effort value. Instead, it's automatically mapped to the closest level that model actually accepts, using this rule:

  1. If the value you sent is one of the five recognized strings and this model accepts it, it's used as-is.
  2. "minimal" is honored as its own real wire value only on the specific models whose provider supports it (see the callout above); on every other model it's treated as a request below the bottom of the scale and resolved by rule 3.
  3. Otherwise (including any level below this model's floor, above its ceiling, an unrecognized string, or "minimal"/"none" on a model that doesn't specially support them), the platform looks for the closest accepted value below what you asked for (or below the default of medium, if what you sent wasn't a recognized string at all) — i.e., it prefers to fall back to something cheaper and faster rather than more expensive than requested.
  4. If nothing accepted exists below, it looks upward instead and uses the closest accepted value above.

In practice this means: asking a model for a level below its floor gets you that floor; asking for a level above its ceiling gets you that ceiling; and an unrecognized string falls back from the platform default (medium) using the same rule. You will never get an error for this — you may simply get a different effort than the one you asked for, so if precise effort matters, check the model's actual behavior rather than assuming your requested string was honored verbatim.

What you get back

The reasoning pass is internal to the model call. /v1/chat/completions returns only the final answer in message.content, formatted exactly like a response from a non-reasoning model — there is no separate reasoning-trace field in the response body, streamed or not. Setting thinking and reasoning_effort changes how the model arrives at its answer (and therefore the token usage and latency you're billed and measured on), not what shape the response takes.

Request examples

Replace your-model-id with a real id from Models whose capabilities you've already checked.

Tier 1 — requesting a specific effort level:

json
{
  "model": "your-model-id",
  "messages": [{ "role": "user", "content": "..." }],
  "reasoning_effort": "high"
}

Tier 1 — requesting "minimal" directly (honored as-is only on models whose provider supports that exact wire value; clamped to that model's floor, reasoning still on, everywhere else):

json
{
  "model": "your-model-id",
  "messages": [{ "role": "user", "content": "..." }],
  "reasoning_effort": "minimal"
}

Tier 1 — requesting "none" directly (equivalent to thinking: false):

json
{
  "model": "your-model-id",
  "messages": [{ "role": "user", "content": "..." }],
  "reasoning_effort": "none"
}

Tier 1 or 2 — asking the model not to reason (best-effort, see caveat above):

json
{
  "model": "your-model-id",
  "messages": [{ "role": "user", "content": "..." }],
  "thinking": false
}

Tier 2 — effort field sent but has no effect, since this model has no effort control:

json
{
  "model": "your-model-id",
  "messages": [{ "role": "user", "content": "..." }],
  "reasoning_effort": "max"
}

Accepted (HTTP 200). The model reasons at its own fixed internal default; "max" is discarded server-side and never reaches the model.

Tier 3 — both fields sent to a model with no reasoning support:

json
{
  "model": "your-model-id",
  "messages": [{ "role": "user", "content": "..." }],
  "thinking": true,
  "reasoning_effort": "high"
}

Accepted (HTTP 200). Both fields are dropped before the request reaches the model; the response is identical to one sent without either field.