# Chat Completions still works. Your tools may not.

> Chat Completions is still supported, but GPT-6 Astra's tools need Responses. Dated API status, every parameter change, silent breaks and a 540-call test.

- Published: 2026-09-25
- Last reviewed: 2026-09-25
- Data as of: 2026-09-25
- Article slug: chat-completions-to-responses-api
- Author: [Glevd](https://x.com/glevd)
- Reading time: 11 minutes
- Topics: openai, api, responses-api, migration, tool-calling, deprecation
- Canonical URL: https://benchlm.ai/blog/posts/chat-completions-to-responses-api

OpenAI has not deprecated Chat Completions. On September 25, 2026, its migration guide still called the endpoint supported, and its deprecations page carried no shutdown date for it.

Assistants was the API that shut down, on August 26, 2026.

Pressure to move comes from the models. Since GPT-5.4, Chat Completions has run tool calls only with reasoning turned off, and GPT-6 Astra, released September 3, cannot call tools there at all.

The model you want sets your migration date.

We had the same decision to make. Our own runner, the one behind our [structured-output tests](/blog/posts/test-structured-output), only spoke Chat Completions, so on September 25 we taught it Responses and sent the same 90 support-ticket calls through both endpoints on three OpenAI models.

The answers barely moved. Everything around them did.

## Assistants shut down. Chat Completions did not.

OpenAI's vocabulary settles most of the confusion. On its deprecations page, a deprecation always comes with a shutdown date, and "legacy" means an endpoint or model that no longer receives updates. Chat Completions has neither label: the page has no Chat Completions entry, and the migration guide describes it as supported while recommending Responses for new projects. OpenAI reserves "legacy" for the older `v1/completions`, and three of its models, `gpt-3.5-turbo-instruct`, `babbage-002` and `davinci-002`, retire the day this guide goes up. [What "deprecated" means](/blog/posts/what-deprecated-means) walks through the vocabulary, and OpenAI's own [deprecations page](https://developers.openai.com/api/docs/deprecations) is the source for every shutdown date.

*OpenAI's deprecations page, migration guide and changelog, read September 25, 2026.*

| API | Status | Date |
| --- | --- | --- |
| Chat Completions | Supported, no shutdown date | None announced |
| Responses | Recommended for new projects | Released March 11, 2025 |
| Assistants | Shut down | August 26, 2026 |
| Completions (legacy) | Three models retire | September 28, 2026 |
| Realtime beta | Removed | May 12, 2026 |
| Reusable prompts | Scheduled to shut down | November 30, 2026 |
| Evals | Read-only, then shut down | October 31 and November 30, 2026 |

Assistants users had a year of notice, from August 26, 2025, and the replacement OpenAI names is the Responses API with the Conversations API. Anyone who waited has lost one path: the Assistants call that retrieved thread messages no longer works, so a backfill now has to start from messages you stored yourself. OpenAI's Assistants guide also described a shortcut, turning each assistant into a reusable prompt object in the dashboard, and then warned that prompt objects are being deprecated too. They shut down on November 30, 2026. A migration that lands there moves twice.

## Tool calling is where Chat Completions runs out

Text in, text out still works on both endpoints for most current models. Tools are where they part. Starting with GPT-5.4, Chat Completions accepts tool calls only when `reasoning_effort` is `none`. GPT-6 Sol and GPT-6 Luna, released September 22, carry the same rule on their model pages. GPT-6 Astra goes further: it has no `none` setting, so it cannot call tools on Chat Completions at all, and OpenAI's changelog entry for the launch says tool calling requires the Responses API.

*OpenAI's model pages, reasoning guide, migration guide and deprecations page, read September 25, 2026.*

| If you need | Chat Completions | Responses |
| --- | --- | --- |
| Tools on GPT-6 Astra | Not available | Available |
| Tools with reasoning on, GPT-5.4 and later | Not available | Available |
| Pro reasoning mode | Not available | `reasoning.mode: pro` |
| Nine pro and codex models | Not supported | Supported |
| File search, code interpreter, MCP | Not available | Available |
| `gpt-audio-1.5` | Supported | Not supported |

Nine model pages list Chat Completions as not supported: `gpt-5.5-pro`, `gpt-5.4-pro`, `gpt-5.2-pro`, `gpt-5-pro`, `o3-pro`, `o1-pro`, `gpt-5.3-codex`, `gpt-5.2-codex` and `gpt-5.6-cyber`. Pro retirements push harder still. `o1-pro` shuts down on October 23, 2026, and the `o3-pro` and `gpt-5-pro` snapshots on December 11, and OpenAI's named replacement for all three is `gpt-5.6-sol` with `reasoning.mode` set to `pro`, a setting that exists only in Responses. Computer use, image generation and reasoning summaries are also Responses-only. The one move in the other direction is audio: `gpt-audio-1.5` runs only on Chat Completions, and OpenAI lists audio on Responses as coming soon.

So check the model pages for [GPT-6 Astra](/models/gpt-6-astra) and whatever you plan to adopt next, not the endpoint's status. If none of your models is on the wrong side of that table, nothing forces the move yet.

## Every parameter has a new name or a new home

Most of the migration is renaming, and the migration guide covers it well. Pin the table below next to the diff. Two rows matter more than they look. `max_output_tokens` counts reasoning tokens, as `max_completion_tokens` already did, so copy the number unchanged or the comparison stops being fair. And structured output moves from `response_format` to `text.format`, with the schema's `name` and `strict` one level higher. The schema itself does not change, and neither does the case for [checking that valid JSON is also right](/blog/posts/test-structured-output).

*OpenAI's migration guide and the Chat Completions and Responses API references, read September 25, 2026.*

| Chat Completions | Responses |
| --- | --- |
| `messages` | `input`<br><br>, plus<br><br>`instructions`<br><br>for system text |
| `max_completion_tokens` | `max_output_tokens` |
| `response_format` | `text.format` |
| `reasoning_effort` | `reasoning.effort` |
| `verbosity` | `text.verbosity` |
| `logprobs` | `include`<br><br>with<br><br>`message.output_text.logprobs` |
| `web_search_options` | A<br><br>`web_search`<br><br>entry in<br><br>`tools` |
| `n` | Removed, one generation per request |
| `seed`<br><br>,<br><br>`stop`<br><br>, penalties,<br><br>`logit_bias` | Not in the Responses reference |
| `function: {name, …}`<br><br>in each tool | `name`<br><br>at the top of each tool |
| `tool_call_id` | `call_id`<br><br>on a<br><br>`function_call_output`<br><br>item |
| `choices[0].message.content` | Items in<br><br>`output`<br><br>, read by<br><br>`type` |
| `finish_reason` | `status`<br><br>and<br><br>`incomplete_details.reason` |
| `prompt_tokens`<br><br>,<br><br>`completion_tokens` | `input_tokens`<br><br>,<br><br>`output_tokens` |

GPT-6 adds one more constraint on both endpoints. With reasoning effort anything other than `none`, `temperature`, `top_p` and `top_logprobs` have to go, so a request that set temperature to zero for reproducibility needs a different plan for variance: repetitions.

## Seven changes fail without an API error

Renames break loudly, which is the good kind of break. These seven return a 200 and change your results, your costs or your data handling. Our run further down caught three of them in the act.

1. **Usage fields change names.**
   
   A dashboard that reads
   
   `prompt_tokens`
   
   and
   
   `completion_tokens`
   
   reads nothing, because Responses reports
   
   `input_tokens`
   
   and
   
   `output_tokens`
   
   . A token report that drops to zero on migration day is this.
2. **`finish_reason` disappears.**
   
   A check for
   
   `"length"`
   
   never fires again. A truncated response now has
   
   `status: "incomplete"`
   
   with
   
   `incomplete_details.reason`
   
   set to
   
   `"max_output_tokens"`
   
   .
3. **`output[0]` is not always the answer.**
   
   On reasoning models the first output item can be a reasoning item, so code that reads the first item's text fails or reads the wrong thing. Iterate
   
   `output`
   
   by
   
   `type`
   
   , or use
   
   `output_text`
   
   , which only the Python and JavaScript SDKs provide.
4. **Instructions do not follow the chain.**
   
   With
   
   `previous_response_id`
   
   , the earlier response's
   
   `instructions`
   
   are not carried over, so a system prompt sent only on the first turn is missing from the second.
5. **The chain still bills the history.**
   
   `previous_response_id`
   
   saves you sending the earlier turns, not paying for them. OpenAI bills every previous input token in the chain as input on each new turn.
6. **Strict mode switches on.**
   
   Chat Completions functions are non-strict by default. Responses attempts strict mode when
   
   `strict`
   
   is omitted, and quietly falls back to non-strict with
   
   `strict: false`
   
   when the schema cannot be made compatible.
7. **Streams end differently.**
   
   Responses sends typed events and finishes with
   
   `response.completed`
   
   , where the usage now arrives. Its streaming reference documents no
   
   `data: [DONE]`
   
   line and no
   
   `include_usage`
   
   chunk, so a parser written for Chat Completions needs rewriting, not renaming.

Each of these shows up in the first few responses if you look. Log the raw response on both endpoints for a day before trusting any aggregate, because every item on this list corrupts an aggregate first.

## Stored state is the default, and it doesn't travel

Chat Completions is stateless: you send the whole conversation every time. Responses keeps that option and adds two stateful ones, and it turns storage on by default. Unless a request sets `store: false`, OpenAI keeps the response for at least 30 days. Organizations with zero data retention are always treated as `store: false`, and the Conversations API, which keeps items until you delete them, is not eligible for zero data retention at all.

*OpenAI's Responses reference, conversation-state guide and data-controls page, DeepSeek's and OpenRouter's Responses API references, read September 25, 2026.*

| How you carry a conversation | Where it lives | Kept for | On DeepSeek and OpenRouter |
| --- | --- | --- | --- |
| Resend it with<br><br>`store: false` | Your application | Not stored | Works |
| `previous_response_id` | OpenAI | At least 30 days | Rejected or unsupported |
| Conversations API | OpenAI | Until deleted | Unsupported |

That last column is the portability test. DeepSeek's Responses endpoint is stateless and expects the full history on every request, and OpenRouter rejects any request with `store: true` or a `previous_response_id` with a 400 error. An application built on server-side state is tied to OpenAI and to hosts, such as Azure, that store responses the same way. That can be the right trade, but it is a trade, and it belongs in the migration decision rather than in a pull request comment.

Two details catch backfills. OpenAI's own Assistants example creates a conversation from all converted items in one call, while the Conversations API accepts up to 20 items at a time, so batch the import. And if you replay assistant history by hand on GPT-5.5 or GPT-5.4, keep each message's `phase`: OpenAI warns that dropping it can make a preamble read as the final answer.

## A fair test keeps the model and changes the endpoint

The expensive mistake is to switch the endpoint and the model in the same release, then credit or blame the model for whatever moved. Every item in the previous two sections can change a result with the model held still. So test the endpoint the way you would test a replacement model: on [the cases that already fail](/blog/posts/building-custom-llm-benchmark), with everything else fixed.

Pin the model snapshot on both sides. Send the same fixture, the same instructions, the same schema, the same token budget and the same reasoning effort. Interleave the calls, case by case, so a provider incident hits both endpoints, and repeat each case three times. Count schema pass over completed responses, task acceptance over attempted cases, and transport failures on their own line. Then compute cost per acceptable result, because an endpoint that passes the same cases with fewer tokens is a real saving and one that passes fewer is not, whatever the price per token.

We ran exactly that on September 25. GPT-5.6 Terra, GPT-6 Sol and GPT-6 Astra each got the kit's 30 support tickets three times on each endpoint, through OpenRouter with the provider pinned to OpenAI. Instructions, schema, token budget and temperature matched on both sides, and the endpoint that went first alternated from one pair of calls to the next.

*Observed in our runs · 2026-09-25-endpoint-terra, 2026-09-25-endpoint-sol, 2026-09-25-endpoint-astra · 2026-09-25 · each model on Chat Completions and Responses via openrouter.ai with the provider pinned to openai · long-cached prompt · 90 cells per endpoint*

| Measure | gpt-5.6-terra | gpt-6-sol | gpt-6-astra |
| --- | --- | --- | --- |
| Task accepted (C · R) | 82 · 82 of 90 | 84 · 84 of 90 | 84 · 84 of 90 |
| Same answer on both | 82 of 87 pairs | 83 of 87 pairs | 87 of 87 pairs |
| Cache hit (C · R) | 99.7% · 99.7% | 99.7% · 99.7% | 99.7% · 99.7% |
| Input per 1,000 calls (C · R) | $0.555 · $0.555 | $0.555 · $0.555 | $2.775 · $2.776 |
| 200s with no answer (C · R) | 2 · 0 | 0 · 0 | 0 · 0 |
| Reasoning item first (R) | 0 of 87 | 39 of 87 | 9 of 87 |

*C is Chat Completions and R is Responses. Task accepted counts attempted cells, including the ones the gateway refused before any model saw them. Same answer compares the parsed JSON both endpoints returned for the same ticket and repetition. Cache hit is cached ÷ input tokens, and input per 1,000 calls is the gateway's reported prompt cost averaged per call and scaled up, both over calls that reported usage. A 200 with no answer is a response that carried neither a message nor usage. Reasoning item first counts Responses calls whose first output item was a reasoning item rather than the message; Chat Completions has no output array.*

The model did not notice which door the request came through. Task acceptance tied on all three models, and Astra returned the same JSON on all 87 paired calls. Where both endpoints answered and the answers differed, one field changed, a category or a copied sentence, and each of those tickets also changed between repetitions on a single endpoint. At this size that is sampling noise, not an endpoint effect. Terra's tie hides two different losses: Responses flipped a category on two cells, and Chat Completions returned nothing on two others.

The cache did not notice either. Both endpoints read 99.7% of input tokens from the [prompt cache](/blog/posts/prompt-caching) on every model, and on 27 or 28 calls per model a request on one endpoint read a prefix the other endpoint had written a moment earlier. Every call that reported usage was billed exactly its tokens at list rates. For a gradual rollout, the cache stays warm while traffic moves.

What changed was everything around the answer. Usage arrived as `input_tokens` and `output_tokens`, and our readout, written for `prompt_tokens` and `completion_tokens`, would have found no token counts on any Responses call until we mapped the names. On GPT-6 Sol, 39 of 87 Responses outputs started with a reasoning item, so code that treats the first item as the answer would have failed on nearly half of them. Astra did it 9 times, Terra never. One Sol call spent its whole 300-token budget on reasoning and came back `incomplete` with no message, a truncation that a `finish_reason` check no longer sees. And the only replies in 522 completed calls that carried neither a message nor usage came from the endpoint we were leaving: two Terra calls on Chat Completions returned HTTP 200 with nothing in them.

Three limits apply. Every call went through OpenRouter, which may reach OpenAI differently for each endpoint, so this measures the switch as a gateway customer sees it. The fixture is single-turn, with no tools and no stored state, which leaves out the parts of a migration most likely to differ. And the two endpoints shared one cache by design, so the 99.7% neither supports nor rebuts OpenAI's claim of better cache use on Responses. The runner and the receipts are downloadable:

1. [run.mjs](/downloads/evidence-kits/support-extraction-v1/run.mjs)
   
   · JavaScript (ES module) · 20.4 KB · sha256 31b5ff942a04
2. [runs/2026-09-25-endpoint-astra/receipt.json](/downloads/evidence-kits/support-extraction-v1/runs/2026-09-25-endpoint-astra/receipt.json)
   
   · JSON · 275.1 KB · sha256 74576d8abad0
3. [runs/2026-09-25-endpoint-astra/attempts.jsonl](/downloads/evidence-kits/support-extraction-v1/runs/2026-09-25-endpoint-astra/attempts.jsonl)
   
   · JSON Lines · 181.8 KB · sha256 e2347cb043fa
4. [runs/2026-09-25-endpoint-sol/receipt.json](/downloads/evidence-kits/support-extraction-v1/runs/2026-09-25-endpoint-sol/receipt.json)
   
   · JSON · 275.7 KB · sha256 8ac95ff4a587
5. [runs/2026-09-25-endpoint-sol/attempts.jsonl](/downloads/evidence-kits/support-extraction-v1/runs/2026-09-25-endpoint-sol/attempts.jsonl)
   
   · JSON Lines · 182.2 KB · sha256 609f7d82daf9
6. [runs/2026-09-25-endpoint-terra/receipt.json](/downloads/evidence-kits/support-extraction-v1/runs/2026-09-25-endpoint-terra/receipt.json)
   
   · JSON · 275.4 KB · sha256 785769524df4
7. [runs/2026-09-25-endpoint-terra/attempts.jsonl](/downloads/evidence-kits/support-extraction-v1/runs/2026-09-25-endpoint-terra/attempts.jsonl)
   
   · JSON Lines · 182.1 KB · sha256 84f7a94b3d95

Files are served as static downloads; if a download is unavailable, copy the visible checklist or try again. Nothing is collected or subscribed when you download.

Only three outcomes are honest. Switch when Responses matches or beats Chat Completions on your failing cases. Keep Chat Completions when it does not, since nothing forces you off it until a model does. Extend the fixture when the two differ by a few cases out of thirty, because that gap is noise. By that rule our fixture says switch, with two parser changes: read usage under its new names and the answer by item type. OpenAI's migration guide cites its own internal results, 3% better on SWE-bench and 40% to 80% better cache utilization, which are vendor measurements on vendor workloads. Your fixture is the test that decides.

Teams on Promptfoo can run both sides from one config: its OpenAI provider selects the endpoint by ID, `openai:chat:<model>` or `openai:responses:<model>`. That matters because OpenAI's own Evals product becomes read-only on October 31, 2026, and OpenAI now points its users to Promptfoo. Our [evaluation frameworks comparison](/llm-evaluation-frameworks) covers the alternatives.

```text
Endpoint switch test (model held still)
[ ] Same model snapshot on both endpoints
[ ] Fixture = current failing cases + controls, expected answers frozen
[ ] Same instructions, schema, token budget and reasoning effort
[ ] No temperature, top_p or logprobs where the model rejects them
[ ] Calls interleaved case by case, 3 repetitions each
[ ] Raw responses logged on both sides for the first day
[ ] Usage read as input_tokens / output_tokens before any cost report
[ ] Answer read from output items by type, never output[0]
[ ] Report: schema pass / completed, task acceptance / attempted,
    transport failures, cost per acceptable result
[ ] Decide: switch, keep Chat Completions, or extend the fixture
```

## The endpoint is free. The tools are not.

OpenAI does not price the APIs separately: Responses, Chat Completions, Batch and the rest bill tokens at the model's input and output rates. Those rates are on the [OpenAI pricing page](/openai/api-pricing). What Responses adds is access to built-in tools. Their tokens bill at the model's rates like any others, and most of them add a fee of their own.

*OpenAI's pricing page, read September 25, 2026.*

| Built-in tool | Price |
| --- | --- |
| Web search | $10 per 1,000 calls, plus search content tokens |
| File search | $2.50 per 1,000 calls |
| File search storage | $0.10 per GB per day, first 1 GB free |
| Containers (code interpreter, shell) | $0.03 to $1.92 per 20-minute session |

Containers are billed by the minute with a five-minute minimum per session, and the price steps with memory, from 1 GB to 64 GB. File search call pricing applies to the Responses API only. None of these is a reason to avoid the tools, but each is a new line on the invoice that a Chat Completions integration never had.

A rule like Astra's arrives as one line in a changelog. OpenAI published it on September 3, and Radar recorded it the same day with the source attached. [Follow model changes](/radar) for the models you declare, and the next rule that sets a migration date reaches you before a failed request does.

## Frequently asked questions

### Is Chat Completions deprecated?

No. On September 25, 2026, OpenAI's migration guide said Chat Completions remains supported while recommending Responses for new projects, and the deprecations page listed no shutdown date for it. Newer models limit it instead: GPT-6 Astra cannot call tools there, and models since GPT-5.4 call tools there only with reasoning turned off.

### Is the OpenAI Responses API stateful?

It can be. By default Responses stores each response for at least 30 days, and previous_response_id or the Conversations API can carry context from one call to the next. Set store to false and resend the history yourself to keep it stateless. Organizations with zero data retention are always treated as store false.

### Does previous_response_id reduce token costs?

No. It saves you resending the conversation, but OpenAI still bills every earlier input token in the chain as input on each new turn, and instructions from the earlier response are not carried over. What can lower that bill is prompt caching, which discounts a repeated prefix whenever the cache is hit.

### Does the Responses API change the model's answers?

Not in our test. On September 25, GPT-5.6 Terra, GPT-6 Sol and GPT-6 Astra accepted the same number of support tickets on both endpoints, and Astra returned identical JSON on all 87 paired calls. What changed was the response around the answer: usage field names, status fields and reasoning items that can come before the message.

### Is the OpenAI Assistants API deprecated?

It is gone. OpenAI sunset the Assistants API on August 26, 2026, a year after announcing its deprecation, and the call that retrieved thread messages no longer works. The named replacement is the Responses API with the Conversations API. Reusable prompt objects, the other path OpenAI described, are scheduled to shut down on November 30, 2026.

### Can I use the Responses API with Azure OpenAI?

Yes. Microsoft documents the Responses API for Azure OpenAI, keeps response data for 30 days by default, and publishes its own guide for moving from Chat Completions to Responses. Check model availability for your region and deployment type, because Azure's model list and retirement dates can differ from OpenAI's own platform.
