tools together with an explicit reasoning_effort (anything other than none) to /v1/chat/completions can be rejected upstream with a 400: Function tools with reasoning_effort are not supported ....Two ways out: move tool-carrying requests to /v1/responses (keeps both reasoning and tools — recommended), or set reasoning_effort="none" explicitly (keeps the endpoint, gives up reasoning). Requests without tools are unaffected.First, confirm that this is what you hit
There are three ways it shows up. The second one is the easiest to misread.Symptom 1: an explicit 400
param: reasoning_effort. This is an official OpenAI restriction, not an APIYI gateway problem — the same request sent straight to OpenAI behaves identically.
Symptom 2: it works sometimes and fails other times
A single model may sit behind several upstream routes, and not every route enforces this. Our own measurements on 2026-09-02, default group, same key, same time window, six calls per combination:gpt-5.6-sol.
Symptom 3: no error, but the tool is never called
If the model should have called a tool and instead replied with small talk (finish_reason is stop, tool_calls empty), do not start rewriting your prompt. Resend once with reasoning_effort set explicitly to none: if the tool is then called correctly, the problem is the parameter combination, not your prompt.
What the restriction covers
none effort level. All four of low, medium, high and xhigh trigger it in our tests.
reasoning_effort does not trigger it. On the gpt-5.6-luna route that reproduces the 400 deterministically, all four effort levels returned 400, while omitting the parameter returned tool_calls correctly 6 times out of 6. So the minimal emergency fix has two forms: set none explicitly, or drop the parameter entirely.Which way out to pick
none as a stopgap rather than a destination.
It is not only about dodging the error
Even if you never hit the restriction, Responses is the endpoint OpenAI recommends for new projects. Officially: the same reasoning model scores higher on SWE-bench through Responses, cache utilization is substantially better than Chat Completions, and built-in tools such as web search and the code interpreter exist only here. The numbers and details are on Native Calls. The cache point is the one that shows up on your bill: multi-turn agents benefit most from cache hits, and multi-turn agents are exactly the workload most likely to hit the restriction above. How caching is billed and how to read hit rates: Prompt Caching.Which group are you in
What changes in your code
The complete field mapping lives on Native Calls. Here are only the four differences that matter for tool calling, since that is what this page is about:The traps people hit while migrating
output is not choices — do not index into it
output is not choices — do not index into it
output is an array of items that can hold reasoning, message and function_call entries at once, in no guaranteed order or count. Use resp.output_text for text, and iterate filtering on type == "function_call" for tool calls. Never hard-code an index.Renamed parameters: max_tokens, response_format, temperature
Renamed parameters: max_tokens, response_format, temperature
max_tokens (or max_completion_tokens) becomes max_output_tokens; response_format becomes text.format; the system prompt can move out of messages into the top-level instructions. Separately, gpt-5 reasoning models do not support temperature or top_p on either endpoint — remove them and control the model through reasoning.effort instead.Every usage field is renamed
Every usage field is renamed
usage.prompt_tokens becomes usage.input_tokens, completion_tokens becomes output_tokens, and cache hits live in usage.input_tokens_details.cached_tokens. Update your usage accounting at the same time, or it will silently record zeros.Multi-turn: managing history yourself always works; chaining depends on your group
Multi-turn: managing history yourself always works; chaining depends on your group
input array yourself, appending each turn’s output verbatim. That holds in every group and for every model, and it is what the example above does.Chaining with previous_response_id did work in the default group on 2026-09-02 — gpt-5.6-sol, terra, luna and gpt-5.4 all recalled the previous turn, store defaults to true, and sending store: false then chaining correctly reports that the previous response cannot be found. Retrieving history with GET /v1/responses/{id} is still unavailable. Verify it in your own group before you depend on it. Background: Multi-Turn Conversations.Streaming is a semantic event stream, not delta concatenation
Streaming is a semantic event stream, not delta concatenation
delta increments; Responses streams typed events such as response.output_text.delta and response.function_call_arguments.delta. Your streaming parser has to be rewritten rather than reused. See Native Calls.Verifying the migration
Do not stop at HTTP 200. Walk these four checks:Confirm output really contains function_call
[i.type for i in resp.output] — you should see function_call, preceded by reasoning at higher effort levels. Only a message means the tool was never called.Confirm your usage fields still read values
usage.input_tokens and output_tokens are non-zero, and that output_tokens_details.reasoning_tokens moves with the effort level.Confirm cache hits start appearing
usage.input_tokens_details.cached_tokens rise above zero. This is the most direct billing benefit Responses has over compatibility mode.Replay the request that used to 400
tools plus reasoning_effort combination should now pass consistently. Keep it as a regression case so a future model swap surfaces the problem immediately.When not to migrate
This is not all-or-nothing. Staying on compatibility mode is perfectly reasonable when:- You do not use tool calling — the restriction does not apply and you can send any
reasoning_effort - You call several vendors with one code path — Claude and Gemini only offer
/v1/chat/completionshere, and forking just for OpenAI may not pay off - Your framework or client locks the endpoint — hold the line with
reasoning_effort="none"until it catches up - You are on
gpt-5.2or earlier — outside the affected range
FAQ
What exactly do I lose with reasoning_effort=none?
What exactly do I lose with reasoning_effort=none?
Can I switch endpoints only for requests that carry tools?
Can I switch endpoints only for requests that carry tools?
/v1/chat/completions and move only the tool-carrying path to /v1/responses. Both endpoints use the same key and the same base URL, and pricing is identical.Does the price change after switching endpoints?
Does the price change after switching endpoints?
Are Claude and Gemini affected?
Are Claude and Gemini affected?
/v1/messages or compatibility mode, and Gemini through native or compatibility mode, can both use tool calling and thinking at the same time.Why are the Pro models Responses-only?
Why are the Pro models Responses-only?
gpt-5.4-pro and gpt-5.5-pro are only usable through /v1/responses, and require the SVIP group. They run for a long time and are designed to pair with background mode, which compatibility mode cannot carry. See Native Calls.Is Chat Completions going away?
Is Chat Completions going away?