OpenAI announced on 22 April 2026 that a set of legacy model snapshots would be shut down on 23 October 20261. Six months of notice is generous, and it is easy to spend it. If anything in your systems still calls o4-mini, o3-mini, o1, gpt-4-turbo or gpt-image-1, it has ten days left.
This guide covers that one date: exactly what goes, what OpenAI names as each replacement, what the change looks like to a running request, and how to find and move every caller in the time left. The general method for any retirement, from evaluation to weighted canary, is in the model deprecation migration playbook; this article does not repeat it.
What OpenAI shuts down on 23 October
OpenAI's deprecations page groups these under "Legacy GPT model snapshots", announced 2026-04-221. The table below is that section, with the aliases OpenAI lists next to each snapshot.
| Snapshot | Aliases that go with it | Listed replacement |
|---|---|---|
o1-2024-12-17 | o1 | gpt-5.6-sol |
o1-pro-2025-03-19 | o1-pro | gpt-5.6-sol with reasoning.mode: pro |
o3-mini-2025-01-31 | o3-mini | gpt-5.6-sol |
o4-mini-2025-04-16 | o4-mini | gpt-5.6-terra |
gpt-4o-2024-05-13 | none | gpt-5.6-sol |
gpt-4-turbo | gpt-4-turbo-2024-04-09, gpt-4-turbo-completions | gpt-5.6-sol |
gpt-4-0613 | gpt-4, gpt-4-0613-completions, gpt-4-completions | gpt-5.6-sol |
gpt-4-1106-preview | none | gpt-5.6-sol |
gpt-4.1-nano | gpt-4.1-nano-2025-04-14 | gpt-5.6-luna |
gpt-3.5-turbo-0125 | gpt-3.5-turbo, gpt-3.5-turbo-completions | gpt-5.6-terra |
gpt-image-1 | none | gpt-image-2.5-sunburst or gpt-image-2.5-flare |
The same section removes fine-tuned models built on these bases: ft-gpt-4, ft-gpt-3.5-turbo, ft-o4-mini-2025-04-16, ft-gpt-4.1-nano-2025-04-14, ft-babbage-002 and ft-davinci-002. Their listed replacements are base models — gpt-5.6-sol, -terra or -luna — not new fine-tunes1.
| OpenAI deprecations page, read 2026-10-13 | Also retires | Listed replacement |
|---|---|---|
| o1-2024-12-17 | o1 | gpt-5.6-sol |
| o1-pro-2025-03-19 | o1-pro | gpt-5.6-sol, reasoning.mode: pro |
| o3-mini-2025-01-31 | o3-mini | gpt-5.6-sol |
| o4-mini-2025-04-16 | o4-mini | gpt-5.6-terra |
| gpt-4o-2024-05-13 | — | gpt-5.6-sol |
| gpt-4-turbo | gpt-4-turbo-2024-04-09, gpt-4-turbo-completions | gpt-5.6-sol |
| gpt-4-0613 | gpt-4, gpt-4-0613-completions, gpt-4-completions | gpt-5.6-sol |
| gpt-4-1106-preview | — | gpt-5.6-sol |
| gpt-4.1-nano | gpt-4.1-nano-2025-04-14 | gpt-5.6-luna |
| gpt-3.5-turbo-0125 | gpt-3.5-turbo, gpt-3.5-turbo-completions | gpt-5.6-terra |
| gpt-image-1 | — | gpt-image-2.5-sunburst or gpt-image-2.5-flare |
| Fine-tunes | ft-gpt-4, ft-gpt-3.5-turbo, ft-o4-mini-2025-04-16, ft-gpt-4.1-nano-2025-04-14, ft-babbage-002, ft-davinci-002 | A base model: gpt-5.6-sol, -terra or -luna |
Three details in that list catch teams out.
The aliases go too. o4-mini, o3-mini, o1, gpt-4 and gpt-3.5-turbo are not moving to a newer snapshot; they are listed as retiring with the snapshot they point at1. Code that used an alias precisely to avoid snapshot churn breaks on the same day as code that pinned the date.
Only one gpt-4o snapshot goes. The entry is gpt-4o-2024-05-13, the first gpt-4o snapshot. Nothing in the 22 April section names the bare gpt-4o alias, so check which id each caller actually sends before you treat "gpt-4o" as affected or safe.
gpt-image-1 is a different job. Its replacements are image models with a different quality range: OpenAI's image guide says the 2.5 models add xhigh and max quality, while earlier GPT Image models support quality settings up to high; it documents three recommended sizes plus custom dimensions in multiples of 16 for the 2.5 models2. An image pipeline needs its own test pass, not just a renamed model.
What a shutdown means for a request
OpenAI's definitions are short: a model announced as deprecated "immediately becomes deprecated", and at shutdown "the model or endpoint will no longer be accessible"1. The page describes no grace period and no automatic upgrade on OpenAI's own API. The page does not document the exact error body a retired id returns, so do not write a handler that matches one string. Treat any error on a request that names a retired id as a deployment defect, and alert on it.
Fine-tuned models follow their base. OpenAI's note on fine-tuning says inference on fine-tuned models continues "until the base models are deprecated"1 — and on 23 October these bases are. A separate entry adds that from 6 January 2027 active existing customers can no longer create new self-serve fine-tuning jobs1. If a fine-tune carried behaviour that prompting has not reproduced, plan for prompts, examples or evaluation work now, because a new fine-tune is not on the listed path.
Azure and aggregators keep their own dates
A model served through another platform retires on that platform's schedule. Microsoft's retirement schedule for Azure OpenAI, updated 2026-09-23, lists o1, o1-pro, o3, o3-mini, o3-pro and o4-mini for 19 November 2026, gpt-4o version 2024-05-13 for 9 December 2026, gpt-4.1-nano for 14 April 2027, and gpt-image-1 (a preview there) for 23 October 20263.
| Shutdown or retirement date | OpenAI API | Azure OpenAI (Microsoft's schedule) |
|---|---|---|
| o1 (2024-12-17) | 23 Oct 2026 | 19 Nov 2026 |
| o1-pro (2025-03-19) | 23 Oct 2026 | 19 Nov 2026 |
| o3-mini (2025-01-31) | 23 Oct 2026 | 19 Nov 2026 |
| o4-mini (2025-04-16) | 23 Oct 2026 | 19 Nov 2026 |
| gpt-4o (2024-05-13) | 23 Oct 2026 | 9 Dec 2026 |
| gpt-4.1-nano (2025-04-14) | 23 Oct 2026 | 14 Apr 2027 |
| gpt-image-1 (2025-04-15) | 23 Oct 2026 | 23 Oct 2026 |
Azure also behaves differently after the date. A retired model returns 410 Gone, Standard deployments can be upgraded automatically to the named replacement depending on the deployment's versionUpgradeOption, and provisioned deployments are not auto-upgraded4. A team running the same app against both OpenAI and Azure can see one half break on 23 October and the other half silently change model in December.
Aggregators are less explicit. OpenRouter's o4-mini page carried no shutdown notice when read on 2026-10-135. That is not a promise of continued service: an aggregator can serve a model only while some upstream it uses still does. If an aggregator is in your path, ask it which upstream serves each retiring id after 23 October, and test.
Find every caller
Most teams know where their main application calls OpenAI. The calls that fail on the date are the ones nobody lists: a nightly summarizer, an eval harness, a support macro, a customer-specific model setting saved in a table three years ago.
start here
What was sent
- Provider usage export by key and model
- Gateway or proxy request logs
- Your own request logging, by service
- The model id each response reports
Code and config
- Literal ids in source, tests and notebooks
- Environment variables and secrets stores
- Feature flags and remote config
- Fallback lists and retry wrappers
- Library and framework defaults you never set
Data
- Prompt and agent configs stored in a database
- Per-customer model settings
- Queued and scheduled jobs
- Fine-tuned model ids built on a retiring base
Start from traffic
What was actually sent is the only complete inventory of callers that ran. Pull 30 days of requests grouped by model and by API key from whatever records them: the provider's usage export, your gateway or proxy logs, or your own request logging. Group by the id as sent, not a normalised family name, so o4-mini and o4-mini-2025-04-16 show up as what they are. For each key that sent a retiring id, find the owning service and its owner. A key nobody can name is a finding in itself.
Thirty days misses monthly jobs and anything that runs on demand. That is what the next two passes are for.
Then search code and configuration
Search every repository, including infrastructure and notebooks, for the literal ids. Anchor the pattern so o1 does not match every version string:
# Literal model ids retiring on 2026-10-23, quoted in code, config or YAML.
rg -n --hidden -g '!node_modules' -g '!*.lock' \
-e '["'"'"'`](o1|o1-pro|o3-mini|o4-mini|gpt-4|gpt-4-turbo|gpt-4-0613|gpt-4-1106-preview|gpt-4o-2024-05-13|gpt-4\.1-nano|gpt-3\.5-turbo|gpt-image-1)(-[0-9-]+)?(-completions)?["'"'"'`]' \
-e 'ft[:-](gpt-4|gpt-3\.5-turbo|o4-mini|gpt-4\.1-nano|babbage-002|davinci-002)'Then look where ids are not literals: environment variables and secret stores (OPENAI_MODEL, LLM_MODEL, per-environment overrides), feature-flag and remote-config systems, Helm values and Terraform variables, fallback lists inside retry wrappers, and defaults in the libraries and frameworks you call through. A wrapper that falls back to gpt-3.5-turbo when the primary fails will pass every test until the day the primary has an outage.
Then the data
Products that let users or operators choose a model store that choice. Query every table that holds prompt templates, agent definitions, workspace settings or per-customer model overrides:
-- Adjust table and column names; run against every store that keeps model choices.
SELECT model, count(*) AS rows, max(updated_at) AS last_changed
FROM prompt_configs
WHERE model ~ '^(o1|o1-pro|o3-mini|o4-mini|gpt-4|gpt-4-turbo|gpt-4o-2024-05-13|gpt-4\.1-nano|gpt-3\.5-turbo|gpt-image-1)($|-)'
OR model LIKE 'ft:%'
GROUP BY model
ORDER BY rows DESC;Check queues and schedulers too: a job enqueued on 20 October with a model id in its payload runs after the date with the old id.
What changes when you swap the model
Changing the model string is the smallest part of the migration. The replacements are a different generation, and the request your code sends was written for the old one. Check these against the replacement's own page, not against memory.
Reasoning effort. OpenAI's reasoning guide says supported effort values are model-dependent, from none through max, and that GPT-5.6 defaults to medium when you omit reasoning.effort6. The gpt-5.6-sol and gpt-5.6-terra pages list none, low, medium, high, xhigh and max78. If your o-series code sends a value that is not on that list, find out what the replacement does with it before the date, not after.
Pro mode. o1-pro maps to gpt-5.6-sol with reasoning.mode: pro1. The guide warns that pro mode "performs more model work than standard mode, increasing token usage and cost"6. Budget for it per request, not per model.
Output limits include reasoning. max_output_tokens limits everything the model generates, reasoning tokens and visible output together, and reasoning tokens are billed as output6. A limit tuned for gpt-4-turbo's visible output can truncate a reasoning model's answer. Watch the share of responses that stop on length after the switch.
Context and price shape. Both gpt-5.6-sol and gpt-5.6-terra list a 1,050,000-token context window with up to 922,000 input tokens and 128,000 output tokens. Sol lists $4 input, $0.40 cached input and $20 output per million tokens; Terra lists $2, $0.20 and $12. On both, prompts over 272K input tokens cost twice the input rate and 1.5 times the output rate for the whole request78. Compute cost per completed task on recorded traffic; per-token rates alone do not tell you what a task costs once reasoning length changes.
Endpoints. The Terra page lists Chat Completions, Responses and Batch and marks Realtime, Assistants, Embeddings and Audio as unsupported8. The -completions aliases in the shutdown table are a reminder that some callers still use the legacy text completions shape. Those callers need a request rewrite, not a rename.
A ten-day cut-over plan
1 · today
Inventory
Every caller of every retiring id, from traffic first, then code, config and stored data.
2 · days 2–5
Qualify
Run the listed replacement on recorded requests with the exact parameters your code sends.
3 · days 3–6
Indirect
Point callers at a name you control, so the model behind it is configuration.
4 · days 5–8
Shift
Move traffic in steps; compare errors, truncation, output tokens and cost per task.
5 · day 8
Block
Refuse the retiring ids so stragglers fail loudly in your systems, not on the provider's date.
6 · 23 Oct onward
Watch
Alert on any request still naming a retired id, and on the served model changing.
- Day 1: inventory. Thirty days of traffic by model id and key, then code, config and stored-data searches. One owner per caller.
- Days 2–5: qualify. Run the listed replacement on a few hundred recorded requests per workload with the exact parameters your code sends. Compare task success, refusals, truncation, output and reasoning tokens, and cost per completed task.
- Days 3–6: indirect. Move callers from a hard-coded model id to a name you control — a config key, an alias in your client wrapper, or a gateway route — so the next retirement is a configuration change.
- Days 5–8: shift. Move traffic in stages and keep the old model as a fallback only until the last stage; a fallback to a model that is about to disappear protects nothing.
- Day 8: block. Make your own systems refuse the retiring ids, so a caller you missed fails in staging or in your logs with a clear message, while you can still fix it.
- 23 October onward: watch. Alert on any request that still names a retired id, on errors by model, and on the model id each response reports. Diary the Azure dates if you run there too.
The playbook covers the qualify and shift steps in depth, including a weighted canary; see when a provider retires a model.
Finding and moving callers with INFRO
INFRO is a control plane that sits between your applications and the provider accounts you already hold. You connect your own OpenAI account, OpenAI bills you directly, and INFRO records each request that passes through it. For a retirement, four parts of it apply. All four work only on traffic that goes through INFRO; calls made straight to OpenAI do not appear.
Who still calls a model. GET /v1/usage groups requests, errors and estimated provider cost by model, project, key, route and more, and GET /v1/requests filters by model, project and key, with route=none selecting direct model calls rather than route traffic. GET /v1/requests/export returns the same rows as CSV. The window is bounded by the plan's request history: 7 days on Developer, 14 on Startup, 30 on Team and 90 on Business. See usage analytics and request history.
Stop new usage. A model allowlist at organization, project or key level can block a model with a ! entry, such as !openai/gpt-image-1. A blocked model is refused with 403 and code model_not_allowed, naming the list that refused it, before any provider is called. Route targets and fallbacks remain subject to the same policy.
Change the model without a deploy. An application can name a route, for example "model": "ticket-summary", instead of a model id. The route resolves to targets on your own connections, and editing its targets changes which model serves with no code change. A weighted route with the new model as a zero-weight standby is how the shift step above is done in the console.
Notices and drift. When INFRO deprecates a model in its catalog, the notice appears under the bell in the console and is emailed to owners and admins, with the retirement date, the successor and what in your organization still uses it: requests in the last 30 days, the keys that sent it or allow it by name, and the routes that target it. After cut-over, traffic changes raise a traffic.model_changed finding when a connection starts being answered by a model id it had not reported in the previous 14 days.
One limit to state plainly: of the models on OpenAI's 23 October list, INFRO's model catalog carries openai/gpt-image-1. The o-series and GPT-4 era snapshots are not catalog models, so a request through INFRO cannot name them on an OpenAI connection; it is answered 404 model_not_found. Whether any model answers at all is decided by OpenAI, on your account.
