What is ending, and what OpenAI says to use instead
On 1 October 2026 OpenAI deprecated three model entries that stop answering on 1 April 2027. Its page calls it six months' notice and names a replacement for each1.
| Shutdown | Model ids named | OpenAI's recommended replacement |
|---|---|---|
| 1 Apr 2027 | gpt-5.1, gpt-5.1-2025-11-13 | gpt-6-sol |
| 1 Apr 2027 | gpt-5.3-codex | gpt-6-sol |
| 1 Apr 2027 | gpt-5.4-nano, gpt-5.4-nano-2026-03-17 | gpt-6-luna |
Two details matter for inventory. The dated snapshots are listed next to the short ids, so a caller that pinned gpt-5.1-2025-11-13 is hit the same day as one that sends gpt-5.1. And the page defines the end state plainly: at shutdown "the model or endpoint will no longer be accessible"1. It describes no grace period and no automatic upgrade on OpenAI's own API.
The calendar post already places these three ids on the date line2. This guide is what to do with the five months. If you reach OpenAI models through another platform, the date can differ: INFRO's docs note that Azure OpenAI, Amazon Bedrock and Vertex AI run their own schedules3, and the Azure entries for these three ids were not read here. Perplexity has already removed gpt-5.1, gpt-5.4 nano and other older OpenAI ids from its Agent and Orchestrator APIs on 24 October4, so a caller on that path is past its date.
Shortlist per model
OpenAI's named replacement is the first candidate, not the only one. The point of a shortlist is to test two or three options on your own prompts and keep the loser's results for the fallback decision.
| Current | First candidate | Also test | Why it earns a slot |
|---|---|---|---|
gpt-5.1 | gpt-6-sol | gpt-5.6-terra | The named path; a lower tier is worth one run if gpt-5.1 was used for modest tasks |
gpt-5.3-codex | gpt-6-sol | gpt-5.6-sol | The named path for code work; the 5.6 tier is a same-family reference point |
gpt-5.4-nano | gpt-6-luna | gpt-5.6-luna | The named path for the smallest tier; the 5.6 Luna is the nearest neighbour in the catalog |
List rates move the budget, so write them down before testing. The INFRO catalog records OpenAI's published list rates for the nano family and its neighbours (checked 2026-10-05)5:
| Model | Input per 1M tokens | Output per 1M tokens |
|---|---|---|
| gpt-5.4-nano | $0.20 | $1.25 |
| gpt-6-luna | $0.10 | $0.50 |
| gpt-5.6-luna | $0.20 | $1.20 |
| gpt-6-sol | $2.00 | $10 |
| gpt-5.6-terra | $2.00 | $12 |
Rates are only half of a replacement decision. Output length, reasoning token use and tool-call behaviour change the real cost per task, which is why the test plan below records cost per successful task rather than rate.
Inventory every call site
The October shutdown post makes the case that traffic is the only complete inventory of callers that ran, and that code search catches ids in config, databases, queued jobs and library defaults that traffic misses6. The same three-pass method applies here, with these ids.
- Traffic, 60 days. Thirty days misses monthly jobs; take sixty and group by the model id as sent, not a normalised family, so
gpt-5.1andgpt-5.1-2025-11-13show up separately. Use your provider usage export, gateway request log or your own logging, grouped by key and service. - Code and config. Search every repository, infrastructure repo and notebook for the literal ids.
- Data. Prompt and agent configs in a database, per-customer model settings, queued and scheduled jobs, and eval harness definitions.
#!/usr/bin/env bash
# Anchored so "gpt-5.1" does not match version strings like "gpt-5.10".
PATTERN='(^|[^A-Za-z0-9.-])(gpt-5\.1(-2025-11-13)?|gpt-5\.3-codex|gpt-5\.4-nano(-2026-03-17)?)([^A-Za-z0-9.]|$)'
git grep -nE "$PATTERN" -- . ':!*.lock' ':!node_modules' || true
# Also search outside git: env files, secrets-store exports, DB dumps, CI variables.Then ask OpenAI's own API which models your key lists with a shutdown date. The deprecations page says GET /v1/models returns an optional shutdown_date field, a YYYY-MM-DD string or null when none is announced1:
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
for m in client.models.list():
date = getattr(m, "shutdown_date", None)
if date:
print(m.id, date)Record each finding in one row: id as sent, service, owner, environment, call volume, whether it uses tools or structured output, and the target model. A key nobody can name is a finding by itself.
Codex is often not an application call
gpt-5.3-codex is frequently set in a developer's tool config, not in a service. Check coding-agent settings, CI jobs that invoke an agent, and shared config files in repositories. If your agents run through a gateway, the model id will also appear in its request log. INFRO documents Codex and the OpenAI Agents SDK pointing at it by changing the base URL and key3, which makes those calls visible in the same traffic inventory.
Qualify the replacement before moving traffic
A model swap is a behaviour change. For each workload, build the test set from real traffic rather than synthetic prompts, and keep three things fixed: the prompt, the parameters you actually send, and the grader. I did not read the replacement models' pages for this article, so use each model's own page to check every parameter your code sends: reasoning settings, token limits, temperature, tool and structured-output options, and stop reasons.
Run these checks in order:
- Schema and tool validity. Does the output still parse, and do tool calls still name your tools correctly?
- Task success. Score against a rubric or labelled outcomes. If you use a model as grader, calibrate it first.
- Length and truncation. Longer answers raise cost and can hit your max-token limit; shorter ones can drop required fields.
- Latency. Time to first token and total time under your real prompt sizes, because timeouts are set from the old model's behaviour.
- Cost per successful task. Output tokens times the rate you actually pay, divided by successes.
For gpt-5.4-nano workloads (classification, extraction, routing prompts) the interesting question is whether gpt-6-luna holds label agreement against the nano outputs. For gpt-5.3-codex, run your repository tasks, not generic coding benchmarks, and keep a human review on a sample of diffs. The existing playbook on fallback equivalence covers how to decide whether the loser of this test can serve as a fallback: Is your fallback model good enough?.
Put a name you control in front of each workload
Hard-coded ids are why these migrations take five months of calendar. Before you cut over, make the model a deploy-time or gateway-level setting.
With INFRO, the name of a route is a valid model value3, so a service can send summarizer-prod and the route's targets decide whether openai/gpt-5.1 or openai/gpt-6-sol answers. Weighted targets give you the canary split without a code deploy, and routing rules can send a matching slice (a project, a key, a prompt size) to the replacement first. Without a gateway, the same result needs a config layer in your own code: one table of logical name to model id, read at startup, with a per-request override for tests.
Keep one rule: the replacement is named explicitly. INFRO never answers a request with a different model on your behalf; on the shutdown date it refuses a retired id and names the replacement in the error3. That is a safety net, not a migration plan, and it still means a failed request.
The cutover schedule
Five months, working backwards from 1 April 2027. The competing dates are real: OpenAI shuts the GPT-4o and GPT-4.1 snapshots on 14 January and whisper-1 and the GPT-4o transcription models on 26 February4, so the same team may be migrating three things.
| Window | Work | Exit criterion |
|---|---|---|
| 3–30 Nov | Inventory from traffic, code and data; assign owners; name the logical model per workload | Every row has an owner and a target |
| 1–19 Dec | Build test sets, run the shortlist, record quality, latency and cost per task | One winner per workload, one runner-up |
| 20 Dec–15 Jan | Hold changes over the holidays; finish the GPT-4o and GPT-4.1 move due 14 January | No open work on 14 Jan |
| 18 Jan–12 Feb | Shadow or canary: 5%, then 25% on the lowest-risk workloads | No quality or error regression for a full week at each step |
| 15 Feb–12 Mar | 50%, then 100% workload by workload; the whisper-1 move lands on 26 Feb | Old ids at zero traffic for 7 days |
| 15–31 Mar | Buffer: stragglers, monthly jobs that have not run yet, rollback rehearsal | Nothing sent to a retiring id for 14 days |
Monthly jobs are why March is a buffer. A job that runs on the 20th will first reveal its old id in the month you thought you were done. For those, run the job manually against the replacement in staging in February instead of waiting for the schedule.
Catching stragglers before the date
Three controls make a missed caller visible while it is still harmless.
- Block the old ids early in lower environments. An allowlist that excludes the retiring ids turns a stray staging caller into a policy error you can read, long before production is affected. INFRO's allowlists are per project, and environments separate staging from production.
- Alert on any request naming a retiring id. An organization that sent a retiring model in the last 30 days receives a
model.retiringalert naming the keys and projects that called it, and the console marks the model with its shutdown date in its pickers3. A recorded retirement also appears in theretirementobject onGET /v1/models3. - Review the request log weekly. Group by model id as sent. The goal is a line that falls to zero and stays there; a long tail of two or three requests a day is a forgotten job.
Outside a gateway, the equivalent is your provider usage export on a weekly schedule, and a CI check that fails when the git grep above finds a retiring id.
What to do if a workload is not ready by March
Decide by the end of January which workloads might not be, not on 25 March. For each, there are four honest options: ship the replacement with a known quality gap and a human check; keep a smaller scope on the replacement and queue the rest; swap in a model from another provider you have already qualified; or ask OpenAI about dedicated capacity, which its page says may be possible in some cases1. A fifth option, doing nothing, ends on 1 April with failed requests.
Record the decision with an owner and a date in the same inventory table, so that on 1 April the only remaining failures are ones someone chose.
