On November 2, 2026, Anthropic's release notes added message threads to the Messages API as a public beta behind the message-threads-2026-08-12 header. The idea is simple. Today, every turn of an agent loop uploads the entire conversation again, and the API validates and tokenizes all of it again. With a thread, the API keeps the conversation on its side for a short time, and each later request sends only what is new.
That is the whole feature, and it matters most to one kind of customer: anyone running long tool-calling loops where a request can carry hundreds of kilobytes of history before the model reads the new tool result. Anthropic's stated benefit is a lower and steadier time to first token as the conversation grows. It publishes no latency or token-saving figures on the documentation page, so none appear here.
What follows is the contract as the documentation states it on November 5, 2026: how a thread is created and continued, how fast it expires, which request fields are frozen for its lifetime, how prompt caching interacts with it, which features and organisations are excluded, and what each of the five error codes means. The last section is a decision grid for teams deciding whether to adopt it during the beta.
- 01One parameter, two modes.A create request sends the full conversation with system and tools; every continue request sends only the new messages plus the previous response id. The response is an ordinary message.
- 02A thread is best-effort and short-lived.It expires 5 minutes after its last request and is deleted no more than 1 hour after last use. A continue request that cannot be served returns a 404, and your application must replay the full conversation. You remain the source of truth.
- 03Nothing about the bill changes.Anthropic states that threads do not change pricing or rate limits, and that a thread does not cache your prompt. Prompt caching still needs breakpoints, and a threaded request may carry at most four.
- 04Several customers cannot use it yet.Threads are not eligible for zero data retention, return a 400 for organisations with HIPAA readiness or inference hooks enabled, and do not work with Message Batches, token counting or compaction.
- 05Adopt it where the loop is long and the data policy allows.Agent loops with many tool calls per task gain the most. Short chats, batch jobs and regulated workloads should wait for the beta to widen.
01 — The ChangeWhat changed on November 2
Until this week, the Messages API was stateless by design. Each call carried the system prompt, the tool definitions and every prior message, and the API rebuilt the model's input from scratch. For a ten-turn chat that is a rounding error. For an agent that makes sixty tool calls over an hour, the history dominates every request, and the time the API spends receiving and tokenizing it happens before the model generates a single token.
Anthropic's release notes entry for November 2, 2026 puts the benefit in one sentence: long conversations and agent loops "can now send smaller requests and get a lower time to first token with message threads". The API keeps the conversation on the server, so each later request sends only the new messages. The entry also states the two limits that shape everything else: a thread expires 5 minutes after its last request and is deleted no more than 1 hour after its last use.
The feature is in beta on every current model, from Haiku 4.5 through Opus 5.5 to Fable 5.1 and Mythos 5.1, and on four platforms: the Claude API, Claude Platform on AWS, Anthropic-managed Claude on Google Cloud, and Microsoft Foundry. The documentation notes that message threads are a different thing from the session threads in Claude Managed Agents. If you have read our piece on the Managed Agents update, do not carry its vocabulary over. A message thread is a transport optimisation for people who run their own loop.
A failure case to hold in mind from the start: a thread is not memory. It cannot be continued from a different organisation, workspace, user or service account, and there is no API to list, read or delete one. A team that treats it as session storage will discover on the first 404 that the conversation is gone unless they kept their own copy.
system and tools from the create request, and a fingerprint of the fixed fields used to check later requests. It is held in memory, encrypted under a server-managed key, never written to durable storage, and deleted no more than 1 hour after last use. Files are held by reference, so every file the conversation uses must stay available while the thread is in use.02 — MechanicsCreate, continue, replay
The documentation describes three operations. Create is your existing first request with one addition: "thread": {"type": "create"}. The API stores the conversation, including Claude's reply, under the response id. Continue sends only the messages since that response plus "thread": {"type": "continue", "previous_message_id": "<id>"}, and leaves system and tools out. The thread keeps the values from the create request. Replay is what you do when a continue request returns a 404: send the full conversation again in a new create request and carry on from the new id.
Here is the shape from the cURL example in Anthropic's message-threads documentation, trimmed to the two turns. The second request sets previous_message_id to the id of the first response.
# Turn 1: full conversation, create a thread
curl -sS --fail-with-body https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" \
-H "anthropic-beta: message-threads-2026-08-12" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"cache_control": {"type": "ephemeral"},
"system": "You are a support agent for Acme. Keep replies short.",
"messages": [{"role": "user", "content": "Hi! I have a question about an order."}],
"thread": {"type": "create"}
}'
# Turn 2: only the new message; system and tools stay out
curl -sS --fail-with-body https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" \
-H "anthropic-beta: message-threads-2026-08-12" \
-H "content-type: application/json" \
-d '{
"model": "claude-opus-5-5",
"max_tokens": 1024,
"cache_control": {"type": "ephemeral"},
"messages": [{"role": "user", "content": "How long does standard shipping usually take?"}],
"thread": {"type": "continue", "previous_message_id": "'"$message_id"'"}
}'Two rules follow from the append-only design. Each response id can be continued exactly once, so a loop must always continue from the latest id. And the API does not check the new messages against what it already holds: if you send the previous response again, the request errors, and if you resend a user message it can appear twice. In a tool loop the continue request normally starts with the tool_result blocks that answer the previous turn's tool_use.
The official SDKs wrap all of this in a thread helper. You create it with the same fields as a Messages request, then send one turn at a time. It adds the beta header, leaves system and tools out of continue requests, resends the fixed fields, and replays on a 404 once by itself. Anthropic also notes that the beta tool runner in the SDK now uses a thread by default, which means some teams will be on threads without changing a line.
One example of a step that trips people: a response that ends with stop_reason: "pause_turn" is resumed with a continue request from that response's id and an empty messages list. Sending a new user message while the turn is paused is rejected.
03 — ExpiryThe five-minute clock
The expiry rule is the design decision that makes threads a transport feature rather than a storage feature. A thread expires 5 minutes after its last request, and each response the API stores restarts that clock. Deletion follows no more than 1 hour after the last use. There is no API to list, read or delete a thread; the only way to keep one alive is to send the next request within five minutes.
Five minutes is comfortable for an agent loop that calls a tool, gets a result in seconds and continues. It is not comfortable for a workflow that waits on a human approval, a CI run or a long external job between turns. Those loops will see the 404 often, and the replay path becomes the common case rather than the exception.
The documentation is direct about the consequence. Your application stays the source of truth for the conversation. No response to a create or continue request tells you whether the API stored that turn; you find out on the next continue. Anthropic lists several reasons a continue can fail beyond plain expiry: the previous turn was served but not stored (for example a tool call cut off by max_tokens), a fallback model wrote the previous response, the previous response is still generating, the request comes from a different organisation, workspace, user or service account, or the new messages add something the stored conversation cannot take, such as the first image in a text-only thread.
The failure case worth designing for is the quiet one. A continue request that is retried after a dropped stream can hit thread_already_continued or thread_continue_in_flight, because the server may have finished and stored the turn after your connection went away. The documentation's answer is that replaying is always safe. Our own guide to safe retries across providers covers the same idempotency problem for non-threaded calls.
Expires after 5 minutes
Counted from the thread's last request. Good for tight tool loops; poor for anything that waits on a person or a slow job between turns.
Gone within 1 hour
Anthropic deletes a thread no more than 1 hour after its last use. You cannot see it, extend it or remove it early from your side.
404 means replay
Send the full conversation from your own copy in a new create request, with system and tools, then continue from the new id. The SDK helper does this once for you.
Start over after a refusal
Do not continue a thread after a refusal. The API may already hold the refused turn and a continue request cannot remove it. Create a new thread without that turn.
04 — Fixed FieldsWhat must stay the same for a thread's life
A thread stores a fingerprint of certain request fields and rejects any continue request that changes one. This is where most integration bugs will come from, because agent frameworks routinely vary these fields between turns: switching models for a cheap summarisation step, toggling tool_choice, or changing the thinking budget mid-task. Every one of those produces a 400 with the code thread_fingerprint_mismatch, and the error message names the fields that differ.
| Group | Fields | Rule |
|---|---|---|
| Create-only | system, tools | Sent on the create request only, with any cache breakpoints on them. Sending either on a continue request, even as null, returns a 400. |
| Fixed | model, tool_choice, thinking, mcp_servers (except each server's authorisation token), context_management, output_config, the skills in container, top-level cache_control, the set of anthropic-beta values | Sent on every request with the same values as the create request. A different value returns 400 thread_fingerprint_mismatch. |
| Free | max_tokens, stop_sequences, stream, metadata, service_tier, other unnamed fields | May change from turn to turn. |
Two details matter beyond the table. The API does not store MCP server URLs, MCP authorisation tokens or the container id, so mcp_servers and container must be sent on every request that uses them. And if you use server-side fallback, the fallbacks field must be present on every request of a thread or on none; adding or dropping it mid-thread is a fingerprint mismatch.
The example that will bite teams migrating from Fable 5 or Opus 5: on Fable 5.1, Mythos 5.1, Opus 5.5, Sonnet 5.5 and Haiku 5.5, changing system or tools invalidates the thinking blocks already in the conversation, so a create request that starts a new thread with different tools can return a 400. Anthropic's workaround is to leave every thinking and redacted_thinking block out of the conversation you replay, accepting that the model then answers without that earlier reasoning. This is the same block-binding behaviour we documented in the Fable 5.1 breaking-changes guide, now surfacing through a new door.
05 — CachingCaching is still your job
The most common misreading of this launch will be that a thread caches the conversation. The documentation says the opposite in plain words: a thread does not cache your prompt for you, and prompt caching works as it does without a thread. A thread saves the upload and the server-side tokenization of the history. It does not by itself change what you pay for input tokens.
To get both benefits, Anthropic's recommended pattern is a top-level cache_control on every request of the thread. The API applies it to the last cacheable block of each request's messages, so each turn reads the earlier conversation from cache and writes the new turn to it. Because top-level cache_control is a fixed field, the value must be identical on every request.
The constraint is the breakpoint budget. A request with thread may carry at most four cache_control breakpoints. The top-level one counts as one. Breakpoints placed on system and tools in the create request count again on every continue request. Breakpoints on earlier stored messages do not count. One too many returns a 400 with thread_unsupported_request and unsupported: ["cache_control"]. And because a continue request cannot resend an earlier message, a breakpoint cannot be moved or removed once sent.
The failure case is the replay. If you placed breakpoints on message blocks yourself, the conversation you replay into a new create request still carries them, and five breakpoints in one request is a hard error. Strip them from earlier messages before replaying and keep one on the last block. The SDK helper does this when it replays on its own. For the economics behind why this is worth the care, our September prompt-caching update covers the current cache-read rates.
- Breakpoints per threaded requesttop-level cache_control counts as one
- 4 max
- Breakpoints on system and toolsset on create, counted again on every continue
- Persist
- Breakpoints on earlier stored messagesalready in the thread
- Not counted
- Moving or removing a breakpointcontinue requests cannot resend earlier messages
- Not possible
- Change to pricing or rate limitspricing and rate limits, per the documentation
- None
06 — ExclusionsWhere threads are barred
The exclusions list is short but it removes whole categories of customer. First, data retention. Message threads are not eligible for zero data retention. Anthropic's framing is that a thread is held in memory, encrypted under a server-managed key, never written to durable storage, and deleted within an hour; it also states that using threads does not affect your use of other ZDR-eligible features. A team under a strict ZDR commitment should read that as "not for us yet" rather than as a loophole. The background on which Claude models and features sit inside ZDR is in our retention and ZDR guide.
Second, organisation settings. Organisations with HIPAA readiness enabled, and organisations with inference hooks turned on, get a 400 with thread_unsupported_request and an unsupported value of hipaa or inference_hooks. Third, features: Message Batches (a batch item with thread fails inside the batch results), token counting (count the full conversation instead), compaction and compaction on demand, and context editing apart from clear_thinking_20251015 with keep: "all".
The example that follows from the compaction rule: because a thread is append-only, you cannot replace its early turns with a summary. The documented approach is to write the summary in your own code and start a new thread from it, with system and tools. Teams that already do application-side compaction, the pattern our context-engineering playbook recommends, lose nothing. Teams that leaned on the API's compaction parameter must choose between it and threads for a given request.
The failure case is silent scope creep. Anthropic says the unsupported list can grow, and that a request meeting several conditions gets an error naming only one. The safe handling is generic: on any thread_unsupported_request value you do not recognise, resend the full conversation without thread. The SDK helper offers exactly that behaviour through a continue_unthreaded setting; without it, the helper replays on every turn.
07 — Error CodesThe five error codes, and what each one asks of you
All five are returned before the model runs, so a rejected request uses no tokens and does not touch the thread's expiry timer. error.type is invalid_request_error for the 400s and not_found_error for the 404. Note that a request for a model that does not exist also returns a 404, so check error.details.error_code before replaying.
| Status | error_code | Meaning | What to do |
|---|---|---|---|
| 404 | thread_not_found | The API cannot continue the thread. | Send the full conversation in a new create request. |
| 400 | thread_fingerprint_mismatch | A fixed field differs from the stored value; the message names the fields. | Keep fixed fields identical, or start a new thread to change one. |
| 400 | thread_already_continued | Each response id can be continued once. | Continue from the latest id; if you never received it, replay. |
| 400 | thread_continue_in_flight | Another continue from this id is still running, usually your own earlier attempt. | Let it finish and continue from its id, or replay. |
| 400 | thread_unsupported_request | The request uses a feature or organisation setting threads do not support; details.unsupported names it when present. | Remove the feature, or send the full conversation without thread. |
One behaviour worth testing early: a continue request without previous_message_id, or one that includes system or tools, returns a 400 with no error_code. An error handler that switches only on the five named codes will treat those as unknown failures. Match on the absence of a code as well and log the message, which in Anthropic's example spells out the problem in a sentence.
08 — DecisionWho should switch now, and who should wait
The question is not whether threads are good. For the workload they target they are a clear improvement with no price attached. The question is whether your workload is that one, and whether your data obligations allow it during the beta. Four routes cover most of the teams our AI transformation practice works with.
cache_control on every request, and build the replay path before the first deploy.thread field.An example of the first route done well: an SDK-based coding agent that averages forty tool calls per task, keeps its own transcript in a database anyway, and already caches its system prompt. Adding threads is a configuration change and a test of the replay branch. An example of the second route done badly: a customer-support workflow that threads a conversation, waits twenty minutes for an agent handoff, and treats the 404 as a crash instead of a replay. The feature did what the documentation said; the integration did not read it.
09 — ConclusionA thread is a transport, not a memory
Keep your own transcript, cache on every turn, and let the thread shave the upload.
Message threads do one thing: they stop a long agent loop from re-uploading and re-tokenizing its history on every turn. Anthropic states the benefit as a lower, steadier time to first token and publishes no figures for it, so treat it as a latency feature to measure on your own loop rather than a cost cut.
The constraints are all stated and all firm. Five minutes of life, best-effort storage, a 404 that means replay, a frozen set of request fields, four cache breakpoints, and no entry for ZDR, HIPAA, inference-hook, batch, token-counting or compaction workloads. None of them is a defect; together they describe a feature built for one job.
If your loop is that job, the SDK helper makes adoption a small change. Build the replay branch first, keep the transcript on your side, and put a top-level cache breakpoint on every request so the thread and the cache work together. If your loop is not that job, nothing about your bill or your rate limits changes by waiting.