On October 14, 2026 OpenAI posted a deprecation notice that gives four GPT-4 series models three months to live. On January 14, 2027 these snapshots stop answering API calls:
gpt-4o-2024-08-06andgpt-4o-2024-11-20gpt-4o-mini-2024-07-18gpt-4.1-2025-04-14gpt-4.1-mini-2025-04-14
Fine-tunes built on them follow the same schedule as their base models, so a fine-tuned 4o-mini classifier dies on the same day. The recommended replacement for all four is gpt-6-luna. That is not a drop-in swap. Luna is a reasoning model. Its default reasoning effort is medium, and the model page states one limit that will break existing code: Chat Completions supports function calling only with reasoning_effort set to none.
This post covers how to find every call that needs to move, the two ways to move it, a replay test over your own logged prompts, and how to check the bill afterwards.
The price change, and what it hides
On the per-token list price Luna is cheaper than every model it replaces, including GPT-4o mini. The chart shows the standard-tier prices per million tokens.

The catch is that reasoning tokens are billed as output tokens, and medium effort produces them on every call you do not turn them off for. Plain arithmetic on the list prices: a 300-token GPT-4o reply costs $0.003 in output. The same reply from Luna with 2,000 reasoning tokens on top is 2,300 output tokens, or $0.00115. That is still cheaper, but against GPT-4o mini ($0.00018 for the same 300 tokens) Luna at medium effort costs about six times more. If you moved off 4o mini for price, measure before you celebrate.
Step 1: find every call
Model names hide in three places: your code, your config, and third-party tools that hold their own key. Start with the code:

grep -rnE 'gpt-4o|gpt-4\.1' --include='*.py' --include='*.ts' --include='*.js' --include='*.go' --include='*.yaml' --include='*.env*' .
Then ask the API. The List models endpoint returns a shutdown_date field for models that have one. This script prints every model your key can see that has a date set:
from openai import OpenAI
client = OpenAI()
for m in client.models.list():
shutdown = getattr(m, 'shutdown_date', None)
if shutdown:
print(m.id, shutdown)
Fine-tuned models appear in that list as ft:gpt-4o-mini-2024-07-18:.... Also check the usage dashboard, grouped by model, for traffic you did not find in code. That traffic is usually a tool or a forgotten cron job. For vendor tools that use your key, ask the vendor which model they will move to, and get the date in writing.
Step 2: pick a path per integration
Path A: stay on Chat Completions, reasoning off
This is the smallest diff, and it is the only option on Chat Completions if the call uses tools. Change the model name and add reasoning_effort='none':

from openai import OpenAI
client = OpenAI()
tools = [{
'type': 'function',
'function': {
'name': 'get_order_status',
'description': 'Look up an order by its number',
'parameters': {
'type': 'object',
'properties': {'order_id': {'type': 'string'}},
'required': ['order_id'],
},
},
}]
resp = client.chat.completions.create(
model='gpt-6-luna',
reasoning_effort='none',
messages=[{'role': 'user', 'content': 'Where is order 10432?'}],
tools=tools,
)
msg = resp.choices[0].message
for call in msg.tool_calls or []:
print(call.function.name, call.function.arguments)
If you leave out reasoning_effort, the default is medium, and a tool-using Chat Completions call is outside what the model page says is supported. Pin the value explicitly in every call site, not only in a shared helper that some code paths skip.
Path B: move to the Responses API, keep reasoning
Tools with reasoning on need the Responses API. The tool schema is flatter: name, description and parameters sit at the top level, not under a function key. Tool calls come back as output items of type function_call:
from openai import OpenAI
client = OpenAI()
tools = [{
'type': 'function',
'name': 'get_order_status',
'description': 'Look up an order by its number',
'parameters': {
'type': 'object',
'properties': {'order_id': {'type': 'string'}},
'required': ['order_id'],
},
}]
resp = client.responses.create(
model='gpt-6-luna',
reasoning={'effort': 'low'},
input='Where is order 10432?',
tools=tools,
)
for item in resp.output:
if item.type == 'function_call':
print(item.name, item.arguments, item.call_id)
print('reasoning tokens:', resp.usage.output_tokens_details.reasoning_tokens)
To return a tool result you send an input item of type function_call_output with the same call_id. That is a bigger change to your agent loop than Path A. It is worth doing where the task benefits from reasoning, such as multi-step tool use or ambiguous requests. For a classifier or an extractor, Path A is usually the better fit.
Step 3: replay your own prompts
Do not judge the switch on a demo prompt. Take about 50 real requests from your logs, run them through the old and new model, and compare what your code actually consumes: which tool was called, with which arguments, and how long it took. This script reads a JSONL file with one {"messages": [...]} object per line:
import json
import sys
import time
from openai import OpenAI
client = OpenAI()
TOOLS = json.load(open('tools.json')) # your Chat Completions tool list
def run(model, messages, **extra):
t0 = time.time()
r = client.chat.completions.create(model=model, messages=messages, tools=TOOLS, **extra)
ms = int((time.time() - t0) * 1000)
m = r.choices[0].message
calls = [(c.function.name, json.loads(c.function.arguments)) for c in (m.tool_calls or [])]
return calls, m.content, ms, r.usage.completion_tokens
same = total = 0
for line in open(sys.argv[1]):
msgs = json.loads(line)['messages']
old = run('gpt-4o-2024-08-06', msgs)
new = run('gpt-6-luna', msgs, reasoning_effort='none')
total += 1
if old[0] == new[0]:
same += 1
else:
print('DIFF', json.dumps(msgs[-1])[:120])
print(' old:', old[0], old[2], 'ms')
print(' new:', new[0], new[2], 'ms')
print(f'{same}/{total} identical tool calls')
python replay.py logged_prompts.jsonl
An identical tool call is the bar for structured paths. For free-text replies, read the diffs yourself. Luna's knowledge cutoff is May 18, 2026, against October 2023 for GPT-4o, so answers about recent products, prices or APIs will change, and sometimes improve. A system prompt that tells the model "it is 2023" will now be wrong in a new way.
Run Path B integrations through the same loop with client.responses.create, and record output_tokens_details.reasoning_tokens per request. That number is the bill question.


