News

OpenAI's Assistants API Shuts Down August 26: The Migration Checklist

OpenAI's deprecations page carries one row for the whole product: shutdown date 2026-08-26, system "Assistants API", recommended replacement "Responses API and Conversations API". The notice went out on August 26, 2025, so the year of warning ends in eight days. Most of the mapping is mechanical. The part that is not mechanical is that OpenAI's own migration guide routes your assistant configuration through an object that has already been deprecated itself.

August 18, 2026

A long dark service counter under cyan light: a shuttered window with lowered slats at one end, two cases still standing on the floor beneath it, and a stack of cases already moved onto the counter beside a warm amber-lit position at the other end.
The luggage is already on the other counter. The thin line still running between the two ends is the part of your integration nobody inventoried.

What Actually Stops Answering

The deprecation entry is short and does not itemize endpoints: "On August 26th, 2025, we notified developers using the Assistants API of its deprecation and removal from the API one year later, on August 26, 2026." Because the notice names a product rather than a list of URLs, an inventory built by grepping for one path will miss most of the work. Inventory by construct instead.

Search your codebase for the SDK namespaces (beta.assistants, beta.threads), the raw paths (/v1/assistants, /v1/threads), the identifiers you persist in your own database (assistant_id, thread_id, run_id), the polling machinery (runs.create, runs.retrieve, run.status), and the configuration blob that never had an equivalent elsewhere (tool_resources). The stored identifiers matter most: a thread_id column in your own schema is an integration point even though no line of your code mentions OpenAI on that row.

Check the beta header separately from the endpoints

Assistants-era clients often set OpenAI-Beta: assistants=v2 globally rather than per call, and the vector stores endpoints are documented with that same header. Vector stores are not listed in the deprecations table, so the store itself is not scheduled to disappear on the 26th — but what your HTTP client sends is a separate question from what OpenAI is removing. Make one vector store call from a client that does not set the header, today, while you still have a working baseline to compare against.

The Four-Object Mapping

OpenAI's migration guide replaces four concepts. The table below uses the guide's own descriptions:

Assistants API Replacement What changes
Assistants Prompts "Prompts hold configuration (model, tools, instructions) and are easier to version and update"
Threads Conversations Store items beyond just messages
Runs Responses "Provide a set of input items to execute, and get a list of output items back"
Run steps Items "Generalized objects — can be messages, tool calls, outputs, and more"

Conversations are the straightforward half. You create one with POST /conversations and then pass conversation=conversation.id on each responses.create call. The retention asymmetry is the detail worth writing down: response objects are saved for 30 days by default, while conversation objects and their items carry no 30-day TTL. If you skip conversations and chain with previous_response_id instead, you have put a 30-day floor under the history your product treats as permanent. There is also no automated thread-to-conversation tool, so the documented approach is to route new chats to the new system and backfill older ones only where you actually need them.

Do Not Migrate Onto Another Deprecated Object

Take the first table row literally and you will do this migration twice. On June 3, 2026, OpenAI "notified developers using reusable prompts in the dashboard and API that reusable prompt objects are being deprecated." The v1/prompts API shuts down on November 30, 2026 — 96 days after the Assistants API does. The recommended migration for prompts is one sentence: "Move reusable prompt content into your application code."

So the useful reading of the assistants-to-prompts row is that your assistant's configuration has to leave OpenAI's storage, not that it has to land in a prompt object on the way out. Skip the intermediate hop. Keep the model, instructions, and tool list in a versioned artifact you control, and pass them inline — the Responses API accepts model, instructions, and tools on the request, with no server-side configuration object required. The same June 3 batch deprecated Agent Builder and the Evals platform, both with a November 30, 2026 shutdown, which is worth knowing before you choose either as a landing place.

// config lives in your repo, versioned with the code that depends on it
export const SUPPORT_AGENT = {
  model: "gpt-5.6-sol",
  instructions: readFileSync("prompts/support-agent.v7.md", "utf8"),
  tools: [{ type: "file_search", vector_store_ids: [process.env.KB_STORE_ID] }]
};

export async function ask(conversationId, userText) {
  const response = await openai.responses.create({
    ...SUPPORT_AGENT,
    conversation: conversationId,
    input: [{ role: "user", content: userText }]
  });
  return response;
}

Runs Polled. Responses Do Not

The Assistants pattern was a create-then-poll loop: create a run, then re-retrieve it while run.status stayed queued or in_progress. A response call returns output directly, so the sleep loop disappears for ordinary requests. For work that genuinely runs long, the replacement is background: true, which puts the response back into a queued or in-progress state you poll with a retrieve call, cancel with POST /v1/responses/{id}/cancel (idempotent — later calls just return the final object), and resume streaming from with starting_after plus the sequence_number you tracked. That resume only works if the response was created with stream=true in the first place, which is a decision you make at creation and cannot retrofit after the connection drops.

The non-obvious break is in your retry logic rather than your happy path. An Assistants run could pause and wait for you to submit tool outputs before continuing, which made the run id a natural idempotency key spanning several HTTP calls. With responses, function calls come back as output items you handle and feed into the next call, so any deduplication, resume, or "did this job already run" check keyed on a run id needs a new key that you own. Pick it before the cutover, not during the first incident.

The Built-In Tools Move on Their Own Terms

File search survives the move with a different shape: tool type file_search, stores attached through vector_store_ids, and result payloads excluded by default until you ask for them with include: ["file_search_call.results"]. Metadata narrowing moves to a filters parameter, and max_num_results is documented as a real trade-off rather than a free win: lowering it "can help reduce both token usage and latency, but may come at the cost of reduced answer quality." If your assistant relied on default retrieval behavior, that default is now yours to choose.

Code interpreter is the one that changes operationally. The tool takes a container, either {"type": "auto"} with an optional memory_limit and file_ids, or an explicit container you create through v1/containers. Memory is 1 GB by default, with 4 GB, 16 GB, and 64 GB available. Containers expire after 20 minutes of inactivity, and on expiry "all data associated with the container will be discarded from our systems and not recoverable" — the metadata stays visible, the files do not. Anyone who treated an Assistants thread as a durable workspace for uploaded files now needs an explicit re-upload path, and the tool is rate limited at 100 requests per minute per organization, which is a capacity number worth checking against your peak before cutover rather than after.

A Cutover You Can Still Reverse

  1. Inventory by construct. SDK namespaces, raw paths, stored identifiers, polling code, tool_resources, and the beta header — not just the string "assistants".
  2. Export before you migrate. There is no automated migration tool, and the deprecation notice does not state what happens to existing assistants, threads, or their messages after the shutdown date. Treat any thread history you have not exported to your own storage as gone on August 26.
  3. Move configuration into code. Model, instructions, and tools in a versioned file in your repository, passed inline. No prompt objects, given their own November 30 date.
  4. Put both paths behind one internal interface. Your application should call your own function, not the provider SDK, while both APIs are answering.
  5. Route new conversations first. New chats go to conversations plus responses; backfill only the older threads a product requirement actually needs.
  6. Cut over with days to spare. Keep the Assistants path as rollback only while it still answers. After the 26th, rollback means a fallback you have tested separately, not pointing traffic back at a removed API.

The shape of this work is not specific to OpenAI: a dated provider removal, a replacement with a different object model, and a window that closes whether or not your team is ready. We walked the same pattern through Google's image endpoints in the Imagen 4 shutdown migration, and the general method for changing an API contract without breaking the clients on the other side is in the AI API contract change plan. If your integration also needs to survive the days around the switch, the timeout, retry, and fallback patterns in the AI reliability chapter apply directly to the dual-path window above.

Sources checked August 18, 2026