Short answer: no. ChatGPT remembers you; the OpenAI API does not. In Chat Completions, "conversation state must be managed manually" (OpenAI, Migrate to the Responses API): each request carries the conversation you want the model to see, and the model knows nothing else. The Responses API can store and chain a conversation for you, but that is the conversation, not a memory of it. Every earlier turn is still sent to the model and billed as input.
So an agent built on the API needs its own memory. This guide covers what OpenAI provides, what it costs, where it stops, and how to add long-term memory without building a retrieval system.
Is ChatGPT's memory available through the API?
No. The memory in the ChatGPT app (saved memories, chat history it refers back to) is a feature of the app. The API reference has no memory endpoint: there is no /v1/memory to call and no setting that turns memory on for API requests. Pages that show one are describing something that does not exist.
What the API does have is ways to carry a conversation forward, listed below. None of them reads or writes the memory a ChatGPT user sees.
What OpenAI gives you
| Option | What it does | What it does not do |
|---|---|---|
| Chat Completions | You send the full messages array on every call | Keep anything between calls |
Responses with previous_response_id | Chains a response to the one before, so you send only the new input | Shrink the history: all earlier input tokens are billed as input again |
| The Conversations API | Stores a conversation's items under a durable id | Decide what the model should still see |
Compaction (context_management) | Replaces old context with an encrypted item when a token threshold is crossed | Give you readable facts, or bring back details on demand |
| Agents API (beta) | Runs the Codex harness with OpenAI-managed sessions, orchestration and compaction (overview) | Work as a memory for the agent loop you already have: it is a different runtime |
Sources for the first four: OpenAI's guides on conversation state and compaction.
Each of these is about carrying the conversation forward. None decides what an agent should keep in mind after hundreds of turns, and none brings a detail from three weeks ago back when the user mentions it again. That is the gap long-term memory fills. We go deeper in previous_response_id and the Conversations API and OpenAI compaction vs a memory layer.
Does OpenAI store my API conversations?
By default, yes, for a while. From OpenAI's docs, checked 12 November 2026:
- Responses are stored for 30 days by default. "Response objects are saved for 30 days by default." Set
store: falseto turn it off (conversation state). - Chat completions are stored by default for new accounts, and
store: falseturns that off too (Migrate to the Responses API). - Conversations have no 30-day expiry. "Conversation objects and items in them are not subject to the 30 day TTL." The data controls table lists
/v1/conversationsas kept until deleted (Data controls). - Zero Data Retention forces
storetofalseon/v1/responsesand/v1/chat/completions, whatever the request says (Data controls).
Stored is not remembered. A stored response is something you can retrieve or chain to; the model still sees only what the next request carries.
How much does it cost to resend history?
Every call pays for the whole conversation so far. If each turn adds about 1,000 tokens, the input you are billed for grows like this, whether you resend the history yourself or chain with previous_response_id:
| Turn | Input tokens on that call | Cumulative input billed |
|---|---|---|
| 10 | about 10,000 | about 55,000 |
| 50 | about 50,000 | about 1.3 million |
| 100 | about 100,000 | about 5 million |
| 200 | about 200,000 | about 20 million, if it still fits |
OpenAI's conversation state guide is explicit that chaining does not change this: all previous input tokens for responses in the chain are billed as input tokens. Prompt caching lowers the price of a repeated prefix, but the model still reads it, and at some turn it no longer fits the window. The previous_response_id guide works through the cached-input numbers.
What long-term memory has to do
- Keep the request under the context window, on every call, without losing the thread.
- Keep what was learned after the turns that taught it leave the window.
- Bring old things back when the conversation turns to them.
- Stay out of the way: the agent loop, the model and the key should stay yours.
The do-it-yourself options
| Approach | How it works | Where it falls short |
|---|---|---|
| Rolling buffer | Keep the last N messages | Everything before the slice is gone: names, decisions, the user's goal |
| Database log | Save every message, reload the conversation | Reloading all of it is the cost problem again; reloading some needs a rule |
| Running summary | A model rewrites old turns into a summary | Detail goes, and the summary drifts as it is rewritten |
| Vector store | Embed messages, search on each turn | Order and recency are lost; you still write the code that builds the prompt |
| A memory service | Hand the conversation to a service built for this | You depend on a vendor; pick one that fails open |
Each piece is easy to start and hard to tune. The hard part is not storing messages; it is deciding, on every call, what the model should see. We compare hosted options in Mem0 alternatives and Zep alternatives.
Memory before the request vs memory as a tool
There are two places to put memory in an agent loop:
- As a tool the model calls. The model decides when to search memory. It forgets to, or searches for the wrong thing, and every lookup is an extra round trip.
- Before the request. Memory builds the request before the model runs, so what the model should know is already in front of it.
Threadless AI works before the request. There is no memory tool to search with and no runtime MCP server: memory is the context the agent runs in. The one tool we add is the note tool, which the model uses to write facts down when old history is about to leave its view (see the note tool pattern).
Long-term memory with three calls
Threadless AI does all four jobs as a service. You send what is new; you get back the request, ready to submit with your key.
from openai import OpenAI
from threadlessai import NOTE_RESULT, Threadless, is_note_call
openai = OpenAI()
memory = Threadless()
memory_id = memory.memories.create()["id"] # one per conversation
def send(text: str):
new_messages = [{"role": "user", "content": text}]
while True:
request = memory.chat.decorate(memory_id, new_messages, {"model": "gpt-5", "tools": [memory.chat.note_tool]})
reply = openai.chat.completions.create(**request)
memory.chat.report(memory_id, reply)
message = reply.choices[0].message
if not message.tool_calls:
return message.content
new_messages = [message.model_dump(exclude_none=True)]
for call in message.tool_calls:
output = NOTE_RESULT if is_note_call(call.function.name) else run_tool(call)
new_messages.append({"role": "tool", "tool_call_id": call.id, "content": output})The same loop in TypeScript:
import OpenAI from 'openai';
import { isNoteCall, NOTE_RESULT, Threadless } from '@threadlessai/sdk';
const openai = new OpenAI();
const memory = new Threadless();
const tools = [memory.chat.noteTool /* , ...your own tools */];
export async function send(memoryId: string, text: string) {
let newMessages: Array<Record<string, unknown>> = [{ role: 'user', content: text }];
for (;;) {
const request = await memory.chat.decorate(memoryId, newMessages, { model: 'gpt-5', tools });
const reply = await openai.chat.completions.create(
request as unknown as OpenAI.ChatCompletionCreateParamsNonStreaming,
);
memory.chat.report(memoryId, reply);
const message = reply.choices[0].message;
if (!message.tool_calls?.length) return message.content;
newMessages = [{ ...message }];
for (const call of message.tool_calls) {
if (call.type !== 'function') continue;
const output = isNoteCall(call.function.name) ? NOTE_RESULT : await runTool(call);
newMessages.push({ role: 'tool', tool_call_id: call.id, content: output });
}
}
}What comes back from decorate is a normal Chat Completions request with:
- your system message, first;
- a facts block: the facts from older messages that are no longer sent word for word;
- the latest messages, word for word;
- a recall block before the user's message when it touches something old;
- a note ask at the end when older messages are about to stop being sent word for word, so the model notes their key facts first.
There is no vector database to run and nothing to tune. Everything runs on our side, inside the one memory the call names. Your OpenAI key stays in your process: the request goes from your code to OpenAI, never through us.
What if the memory service is down?
Your model call still goes ahead. When decorate cannot reach us, the SDK builds the request from a local tail of recent turns kept in your process, and tells your onError callback. No facts are added and nothing is recalled during the outage, and the memory picks up from the next successful call. See What happens when memory is down.
Does it work with the Responses API?
Yes. memory.responses is the same three calls for Responses items. Drop previous_response_id and store: we hold the history, so the request carries what the model should see. See Add memory to a Responses API agent.
Questions people ask
Can I enable ChatGPT memory in the API?
No. ChatGPT's memory belongs to the ChatGPT app and there is no switch or endpoint for it in the API. To give an API agent memory you carry state yourself or use a memory layer.
Does the Assistants API have memory?
The Assistants API kept threads of messages, not a memory, and it is gone: OpenAI sunset it on 26 August 2026 (Deprecations). Threads map to the Conversations API. See Migrating from the Assistants API.
Does the Responses API remember earlier turns?
Only if you ask it to, with previous_response_id or a conversation. Otherwise each call sees only the input it carries. Either way the model rereads the whole history on every call.
Is memory the same as conversation state?
No. Conversation state is the transcript, carried forward. Memory decides what of that transcript the model should see now, keeps what was learned after the turns leave, and brings old details back when they matter.
Does adding memory change my model or prompts?
No. You choose the model and write the instructions. decorate returns the request you would have sent, with the history managed and our facts, recall and note ask added as instruction messages.
Does OpenAI keep my API data for 30 days?
Stored responses are kept for 30 days by default, and store: false turns that off. Conversations are kept until you delete them. Abuse monitoring logs are separate; OpenAI's data controls page covers both.