OpenAI Shuts Down the Assistants API on August 26, 2026: A Migration Guide for Owning Your Agent's Memory Instead of Renting It

If you built an AI agent on OpenAI's Assistants API, you have a deadline now, not a suggestion. OpenAI's own deprecations page confirms it: the Assistants API — assistants, threads, and runs — is removed from the API on August 26, 2026. OpenAI announced the sunset exactly one year in advance, on August 26, 2025, via its developer community and the @OpenAIDevs account: "We're winding down the Assistants API beta. It will sunset one year from now." There is no extension, no degraded fallback mode, no second grace period after that date — every call to /v1/assistants, /v1/threads, and /v1/threads/runs simply starts returning errors.
That forces a rewrite of whatever code manages your agent's conversation state. Most migration guides treat that as a chore: swap the old SDK calls for new ones, ship it, move on. It's worth treating it as something else — the one moment you're touching this code anyway, and therefore the cheapest moment to decide where your users' conversation history actually lives.
What's actually going away, and what survives
The Assistants API bundled four concepts that the Responses API breaks apart:
| Old (Assistants API) | New (Responses + Conversations API) | What changed |
|---|---|---|
| Assistants | Prompts | Configuration (model, tools, instructions) now lives as a versioned object created in the dashboard, reusable across Chat, Realtime, and the Responses API |
| Threads | Conversations | Storage moves from a message-only list to a generic stream of items (messages, tool calls, tool outputs, reasoning) |
| Runs | Responses | The async run-and-poll model is replaced by a single synchronous call: send input, get output |
| Run steps | Items | Generalized objects representing each interaction step |
One thing does not disappear: Vector Stores. They're a standalone resource, and the Responses API's file_search tool consumes them directly via vector_store_ids — confirmed in OpenAI's Assistants File Search docs. If your agent's only stateful dependency was retrieval-augmented search over uploaded files, that part of your architecture barely changes. It's specifically threads and runs — the conversation history and execution state — that go away and need a new home.
The code-level change
The Assistants API required a polling loop: create a run, poll its status until it's no longer in_progress or requires_action, then read the messages back off the thread. The Responses API collapses that into one call:
# Before — Assistants API (polling)
run = client.beta.threads.runs.create(thread_id=thread.id, assistant_id=assistant.id)
while run.status in ("queued", "in_progress"):
time.sleep(1)
run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)
messages = client.beta.threads.messages.list(thread_id=thread.id)
# After — Responses API (synchronous)
response = client.responses.create(
model="gpt-5",
input="What's the status of order #4471?",
previous_response_id=last_response_id, # chains context server-side
)
print(response.output_text)
previous_response_id is the closest analog to a thread: pass the prior response's ID and OpenAI reconstructs context server-side, per the conversation state guide. That's the easy migration path — same server-side persistence model as before, new API shape.
The store: false path — and why it matters more than the syntax swap
The same guide documents a second option that most "how to migrate" posts skip: setting store: false on a Responses call means "Response objects are not saved" server-side at all. Combined with previous_response_id being unavailable in that mode, OpenAI's own docs describe the alternative explicitly — maintain the message history yourself, append every output item (including reasoning items) to your own array, and pass the full history back on each call:
# Stateless mode — you own the history, OpenAI owns nothing between calls
history = load_conversation_from_your_db(user_id) # your DB, not OpenAI's
history.append({"role": "user", "content": user_message})
response = client.responses.create(
model="gpt-5",
input=history,
store=False, # nothing persists on OpenAI's servers after this call returns
)
history += response.output # includes reasoning + tool-call items, per OpenAI's docs
save_conversation_to_your_db(user_id, history)
This is a documented, first-party-supported pattern, not a workaround. The cost is exactly what you'd expect: OpenAI's docs note that with manual history management, "all previous input tokens for responses in the chain are billed as input tokens" on every call, since there's no server-side context to reference. For most conversational agents that's a modest markup, not a redesign — and it buys you something the default previous_response_id path doesn't: your users' conversation history is a table in a database you control, not an object living in OpenAI's Conversations store.
The honest case for and against each path
Before assuming self-hosting memory is automatically the "more compliant" choice, it's worth being accurate about what OpenAI already offers. As of January 2026, OpenAI expanded data residency in Europe to eligible API customers — per the API data residency help article, approved projects can route through eu.api.openai.com for regional storage and processing. If you're already on that program, staying with server-side Conversations and just doing the mechanical API migration is a legitimate, lower-effort choice.
Two caveats worth knowing before you rely on it:
- It requires eligibility and approval — it's not the default for every API key, and features like Zero Data Retention need separate sign-off.
- Regional storage is not the same as jurisdiction independence. OpenAI, Inc. is a US company. The US CLOUD Act (2018) compels US-based providers to produce data in their "possession, custody, or control" in response to a valid US legal order, regardless of where that data is physically stored — a distinction from GDPR-style data-location requirements. Choosing
eu.api.openai.comaddresses the GDPR data-residency question; it does not, on its own, remove US legal jurisdiction over the same data.
If jurisdiction independence — not just storage location — is the actual requirement (common for EU public-sector-adjacent SaaS, healthtech, and fintech), the store: false pattern above is what makes that achievable without switching model providers at all: keep calling OpenAI (or anyone else) for inference, but store the conversation itself in infrastructure you control end to end.
A minimal self-hosted conversation store
If you're rebuilding your persistence layer anyway, here's the shape of it — a Postgres table on an EU-hosted PaaS, holding exactly what the Responses API needs to reconstruct context, and nothing living on a US vendor's servers between requests:
create table agent_conversations (
id uuid primary key default gen_random_uuid(),
user_id uuid not null references users(id),
history jsonb not null default '[]', -- array of Responses API input/output items
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create index on agent_conversations (user_id, updated_at desc);
async function sendMessage(userId: string, message: string) {
const convo = await db.query(
`select id, history from agent_conversations where user_id = $1
order by updated_at desc limit 1`,
[userId],
);
const history = convo.rows[0]?.history ?? [];
history.push({ role: "user", content: message });
const response = await openai.responses.create({
model: "gpt-5",
input: history,
store: false,
});
const updatedHistory = [...history, ...response.output];
await db.query(
`insert into agent_conversations (user_id, history) values ($1, $2)
on conflict (id) do update set history = $2, updated_at = now()`,
[userId, JSON.stringify(updatedHistory)],
);
return response.output_text;
}
Roughly 20 lines. That's the entire delta between "conversation memory lives on OpenAI's servers by default" and "conversation memory lives in a Postgres instance you provision, back up, and can point at any EU host" — including a managed PaaS like sota.io, where the same table would sit behind a database that's provisioned with the app, not a separate service you patch yourself.
Migration checklist
- Inventory what you actually use. If your Assistants only ever used
file_searchover Vector Stores with no custom conversation logic, your migration is mostly config — Vector Stores survive, point the Responses API'sfile_searchtool at the samevector_store_ids. - Move Assistant configs to Prompts in the dashboard — model, instructions, and tool definitions, so the same config works across Chat, Realtime, and Responses.
- Replace the polling loop with a synchronous
responses.create()call. - Decide the storage question deliberately, not by default:
previous_response_id(OpenAI keeps storing your conversations, just under a new name) versusstore: falsewith your own history table (you keep it, wherever you host it). - Backfill existing threads before August 26. OpenAI's migration guide confirms there's no automated thread-to-conversation migration tool — existing thread history has to be read out and written into whichever store you choose while the old endpoints still work.
- Test the token-cost delta of manual history management on your longest-running conversations before committing — it scales with conversation length, not request count.
Whichever path you take, the deadline doesn't move: August 26, 2026, per OpenAI's own deprecations page, with the code already shipped and the docs already published. The only real decision left is whether the rewrite you're forced to do anyway is also the one that gets your users' data off infrastructure you don't control.
See Also
- EU Cloud Sovereignty for Indie Developers: What the CLOUD Act Actually Means for Your Stack — the jurisdiction framework referenced above, for readers weighing regional storage against genuine jurisdiction independence
- Coolify Alternative 2026: What Changes When Nobody Has to Patch the Server — for readers deciding between self-hosting infrastructure themselves and a managed EU PaaS for the database this migration needs
- Best European PaaS Providers 2026: GDPR, DORA, and Real EU Jurisdiction Compared — where to actually host the Postgres instance in the code sample above
EU-Native Hosting
Ready to move to EU-sovereign infrastructure?
sota.io is a German-hosted PaaS — no CLOUD Act exposure, no US jurisdiction, full GDPR compliance by design. Deploy your first app in minutes.