The Assistants API was officially sunset on August 26, 2026, and is no longer available. Applications must move generation, state, tools, and data workflows to Responses. Inventory every Assistant, Thread, Run, and tool, recreate behavior as Responses configuration, migrate application-owned history, then test output and side effects before switching traffic. OpenAI’s official Assistants migration guide confirms the shutdown and object mapping.
What the August 26, 2026 sunset changes
This is an endpoint and object migration, not a model rename. Calls to the old Assistants resources cannot be treated as a temporary warning after the sunset. Code that creates or reads /v1/assistants, /v1/threads, /v1/threads/messages, or /v1/threads/runs needs a replacement path. Do not start a new integration on the old API, and do not build a fallback that assumes old objects will remain queryable.
The current mapping in OpenAI’s guide is:
| Assistants API | Responses platform | Practical meaning |
|---|---|---|
| Assistant | Prompt or request configuration | Keep model, instructions, tool declarations, and output rules in a versioned configuration. The current guide says dashboard prompts can be created from existing assistants, but it also notes that reusable prompt objects are being deprecated. |
| Thread | Conversation or application history | Conversations hold items, including messages, tool calls, and tool outputs. You can also keep state in your own database and send the required items. |
| Run | Response | A Responses request receives input items and returns output items. A separate run object and polling loop are not the central abstraction. |
| Run step | Item | Inspect typed items such as message, function_call, function_call_output, and reasoning items rather than assuming every result is a message. |
Read the Responses API migration guide alongside the sunset guide. It describes Responses as the recommended API for new projects and documents the differences from Chat Completions as well as the input and output shapes.
The new mental model
An Assistant used to be a persistent server-side bundle. A Thread held messages, and a Run executed the Assistant against that Thread. Responses separates those concerns. A request specifies a model, instructions, input, and tools. The result is a typed Response whose output is an ordered list of items.
This design gives your application ownership of orchestration. Your code decides identity, history, allowed tools, argument authorization, retries, and human approval. Stateful options remain available, but they are choices rather than an implicit Assistant lifecycle.
There are three useful state strategies:
- Use a stateless request and pass a bounded list of input items on every turn. This gives your database control of retention and pruning.
- Chain turns with previous_response_id. The conversation state documentation shows this pattern. It is convenient for short-lived flows, but previous input tokens remain part of billing, and storage and retention must match your policy.
- Create a Conversations API object and pass its ID to Responses. Conversations have durable identifiers and can be used across sessions, devices, or jobs. Conversations store items until deleted, so treat the identifier as a reference to retained application state, not as a privacy switch.
Choose one strategy per product flow. Avoid mixing a locally reconstructed transcript, a Conversation, and a previous_response_id chain without a clear source of truth. Duplicate turns can change model behavior, increase cost, and make deletion requests difficult to honor.
Inventory before changing code
Create a migration record for each Assistant ID and each production session path. Record the model, instructions, default parameters, tool schemas, vector stores, files, Code Interpreter usage, response format, metadata, retention expectations, and any code that polls Run status. Search not only the backend but also worker jobs, admin scripts, dashboards, tests, and analytics consumers. A successful text response does not prove that file search, structured output, streaming, or a side-effecting function still behaves the same.
Separate behavior from stored data. Instructions and tool declarations can be recreated from configuration. Thread messages and uploaded files are data assets that require an export or an application-owned copy. If your system never stored user messages outside Threads, decide how to handle those records before deleting anything. The post-sunset guide states that fetching old Thread messages no longer works and recommends using messages already stored by your application.
Recreate the basic request
For a text-only interaction, replace the beta Thread and Run sequence with one Responses call. The input field can be a string or a list of message-like items. Use instructions for stable system-level behavior and keep user content in input. Read ordinary text through response.output_text, but inspect response.output when tools or non-text items are possible.
from openai import OpenAI
client = OpenAI()
response = client.responses.create(
model="gpt-5.6",
instructions="Answer clearly and cite the supplied records.",
input=[{"role": "user", "content": "Summarize the order status."}],
store=False,
)
print(response.output_text)
The endpoint is /v1/responses. The SDK method is client.responses.create. Do not carry over messages as the request keyword, choices[0].message.content as the response path, or a polling loop copied from Runs. If you need stored Responses, make that a deliberate choice. The data controls documentation currently states that Responses application state is retained for 30 days by default or when store is true, subject to the listed exceptions.
Preserve history correctly
If your application owns the transcript, normalize it into Responses input items. A user text part becomes input_text, an assistant text part becomes output_text, and an image becomes input_image with its URL or file reference. Preserve chronological order and any tool-call and tool-output pairs that are needed to explain a prior turn.
The following small example creates a durable Conversation from application-owned history and then sends a new turn:
from openai import OpenAI
client = OpenAI()
conversation = client.conversations.create(
items=[
{
"role": "user",
"content": [{"type": "input_text", "text": "My order is 1842."}],
},
{
"role": "assistant",
"content": [{"type": "output_text", "text": "I can check order 1842."}],
},
]
)
response = client.responses.create(
model="gpt-5.6",
conversation=conversation.id,
input=[{"role": "user", "content": "Is it ready to ship?"}],
)
print(response.output_text)
Do not try to migrate by calling threads.messages.list after the shutdown. A post-sunset system must use records retained by the application. Reconcile user identity, deletion requests, regional rules, attachments, and timestamps before importing, and verify that every Conversation ID belongs to the authenticated user.
Move tools and function calls
Responses tools are declared on the request. Built-in tools such as web search, file search, computer use, Code Interpreter, image generation, and remote MCP are documented in Using tools. Custom functions still need an application-side implementation. The model can request a function, but it cannot authorize or execute your business operation.
The control loop is explicit. Send the first request, inspect response.output for function_call items, validate and execute each allowed function, append the model’s output items and the resulting function_call_output items, then send the next request. For reasoning models, preserve the reasoning items returned with a tool call as shown in the function calling guide.
import json
from openai import OpenAI
client = OpenAI()
tools = [
{
"type": "function",
"name": "lookup_order",
"description": "Return the status of an order owned by the authenticated user.",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
},
"required": ["order_id"],
"additionalProperties": False,
},
"strict": True,
}
]
input_items = [{"role": "user", "content": "Where is my order 1842?"}]
response = client.responses.create(
model="gpt-5.6",
tools=tools,
input=input_items,
)
input_items += response.output
for item in response.output:
if item.type == "function_call" and item.name == "lookup_order":
arguments = json.loads(item.arguments)
result = {"order_id": arguments["order_id"], "status": "packed"}
input_items.append(
{
"type": "function_call_output",
"call_id": item.call_id,
"output": json.dumps(result),
}
)
response = client.responses.create(
model="gpt-5.6",
tools=tools,
input=input_items,
)
print(response.output_text)
Strict mode helps calls follow the schema, but it does not make a caller authorized. Validate the authenticated user, ownership, ranges, enum values, and business state in application code. Use idempotency or a transaction for operations that can charge, delete, publish, or send. Return a structured tool error when execution fails instead of pretending that the requested action succeeded. Set a maximum number of tool turns and record each call, result, and approval decision with sensitive values redacted.
Preserve structured outputs
If the old Assistant used JSON mode or a response schema, map it to the Responses text.format configuration rather than copying response_format unchanged. The structured outputs guide documents the current schema shape and SDK helpers. Validate the parsed result before it reaches a database, a UI, or another tool. A valid JSON document can still contain an invalid order ID, unsafe instruction, or incomplete business decision.
Keep the schema small and version it with the prompt or request configuration. Add required fields, set additionalProperties to false where strict mode requires it, and test refusals, incomplete responses, and schema evolution. Never infer success from a JSON object alone.
Security and data handling after migration
The migration changes the state boundary, so review security as an architecture change. Keep API keys on a trusted server, authenticate sessions, and bind each Conversation or transcript to the server-side user. Never put secrets, authorization tokens, or unrestricted database queries in instructions or tool descriptions.
Use the least powerful tool set for each request. Separate read-only functions from writes, require explicit confirmation for consequential actions, and make authorization checks independent of model output. Treat retrieved files, web pages, and remote MCP responses as untrusted input. Remote MCP servers are third-party services with their own retention policies, and hosted Code Interpreter containers can hold temporary state while active. The data controls guide lists these endpoint-specific limits.
Choose store, a Conversation, or an application-owned transcript for each flow. API data is not used to train OpenAI models without explicit consent, but this does not replace review of retention, access, deletion, regional processing, or vendors. store=false is not a blanket deletion policy and does not make a Conversation ephemeral.
Apply input limits, output limits, moderation where appropriate, and human review for high-impact decisions. OpenAI’s safety best practices specifically recommend adversarial testing for prompt injection, moderation, and human oversight. Log request IDs and typed event names, but redact user content, credentials, function arguments, and tool outputs according to your policy.
Common migration failures
The old endpoint returns an error
Treat requests to Assistants resources after August 26, 2026 as a migration defect. Remove the old client path instead of retrying it. If a background worker still polls Run IDs, deploy the Responses worker and migrate its queue payloads from thread_id and run_id to your session and response identifiers.
The answer is empty or the parser crashes
Responses output is a heterogeneous item list. output_text is convenient for ordinary text, but a tool call, refusal, or incomplete response requires inspection of status and output item types. Never index the first item and assume it is a message.
The model repeats context or cost rises
Choose one state strategy and define a pruning rule. previous_response_id does not make earlier input tokens free, and copying the same transcript into both a Conversation and input duplicates context. Measure input and output tokens in staging with realistic long conversations.
A function executes twice
Retries, parallel tool calls, network timeouts, and client reconnects can replay a call. Give every side-effecting operation an idempotency key based on the call ID and authenticated user, then check the business transaction before applying it. A successful model message is not proof that your function committed exactly once.
Old files or retrieval results disappear
Inventory vector stores, file IDs, expiration rules, and permissions separately from Thread history. Recreate the supported retrieval path, verify access for each tenant, and test citations and empty-result behavior. Do not assume that converting an Assistant configuration also copies file data.
Migration checklist
Use this sequence for each production flow:
- Record the old Assistant, Thread, Run, file, vector store, tool, prompt, and metadata dependencies.
- Copy user-visible instructions and tool schemas into version-controlled configuration.
- Select a Responses model and confirm its tools, multimodal inputs, structured outputs, and regional availability.
- Choose stateless items, previous_response_id, or Conversations as the single state strategy.
- Map messages to input, choices to output, and text extraction to output_text.
- Rewrite function definitions and implement an explicit, bounded tool loop.
- Recreate file search, Code Interpreter, web search, MCP, streaming, and structured output behavior one capability at a time.
- Import only application-owned history, preserving order, identities, attachments, tool calls, and deletion semantics.
- Add authorization, input limits, moderation, idempotency, redacted logs, and human approval for side effects.
- Run golden conversations, adversarial prompts, tool failures, retries, refusals, long contexts, and concurrent sessions.
- Compare user-visible answers, citations, tool effects, token usage, latency, errors, and retention behavior.
- Release behind a feature flag, drain old workers, monitor Responses errors, and keep a rollback path that does not depend on the sunset API.
- Delete obsolete Assistant code and credentials only after exports, audit records, and support procedures are verified.
For the surrounding system design, see the production AI agent architecture guide. For regression datasets and behavioral checks, use the AI agent evals guide.
How to know the migration is complete
The migration is complete when no production path depends on Assistants resources, every session has a deliberate state owner, every tool call is authorized and replay-safe, and the Responses output contract has tests. Keep model, prompt, schema, retention, and failure records. Revisit them when Responses or the selected model changes, because removing the old fallback does not remove ongoing evaluation.