On requests of 500,000 to one million tokens, median time to first token drops by about 35%. That is the figure Anthropic gives for Message Threads, a Messages API feature in public beta since November 2, 2026: the client sends the full conversation once and, after that, only what is new on each turn. Per-token pricing stays the same, because Claude still reads the whole history; what goes away is uploading, validating and tokenizing the entire conversation again on every request.
What changes
Until now the Messages API has been stateless: every agent turn resends the system prompt, the tools and every earlier message and tool result. For a coding agent that makes hundreds of calls per session, that means hundreds of thousands of tokens travelling back and forth before the model starts answering.
With a thread, the first request carries the full conversation plus "thread": {"type": "create"}. Later requests carry only the new messages and "thread": {"type": "continue", "previous_message_id": "<id>"}, the id of the previous response. The server rebuilds the conversation before calling the model. Anthropic says the thread is held encrypted in memory, never written to disk, and expires 5 minutes after the last request (it is deleted at most an hour later).
It is available on the Claude API, Claude Platform on AWS, Microsoft Foundry and Claude Models on Google Cloud (Anthropic managed), for every model, behind the message-threads-2026-08-12 beta header. Pricing and rate limits are unchanged. According to the announcement, it is already on by default for most Claude Code users, which is where the 35% comes from.
Turning it on
The SDK ships a helper that creates the thread on the first turn, adds the beta header, leaves system and tools out of later turns, and replays the whole conversation when the thread is gone:
import anthropic
client = anthropic.Anthropic()
# The helper sends nothing until the first turn
thread = client.beta.messages.thread(
model="claude-opus-5-5",
max_tokens=1024,
cache_control={"type": "ephemeral"},
system="You are a support agent for Acme. Keep replies short.",
)
thread.send({"role": "user", "content": "Hi! I have a question about an order."})
second = thread.send({"role": "user", "content": "How long does standard shipping take?"})The top-level cache_control is optional, but a thread does not cache anything on its own: without cache breakpoints, each turn sends less data, yet nothing is reused from the prompt cache. If you build the requests yourself, the beta header has to go on every one of them.
Versus OpenAI's previous_response_id
OpenAI solved the same problem a while ago in its Responses API, with a different take on storage:
| Message Threads (Anthropic) | previous_response_id (OpenAI) | |
|---|---|---|
| Where state lives | In memory, encrypted, never on disk | Response objects stored for 30 days by default (store: false turns it off) |
| Expiry | 5 min idle; deleted within 1 h | 30 days |
| Branching | No: append-only, each id can be continued once | Yes, from any response still available |
| Tokens billed | The whole conversation, as before | All previous input tokens in the chain |
| ZDR | Not eligible | — |
Anthropic's design is deliberately ephemeral: it exists to take latency out of an active agent loop, not to store your conversation. That is why the docs insist that your application stays the source of truth: keep your own copy of every message and build the full-replay path from day one.
Gotchas and edge cases
systemandtoolsonly on create. Sending either on acontinuerequest, even asnull, returns a 400.model,thinking,tool_choice,output_configand the top-levelcache_controlmust be identical on every turn, or you getthread_fingerprint_mismatch. To change any of them, start a new thread.- The 404 is part of the flow.
thread_not_foundcomes back when the thread expired, when a fallback model wrote the previous response, when you switch key or workspace, or when the API did not store the turn (for example, a tool call cut off bymax_tokens). The response does not say which: replay the full conversation in acreaterequest. - Not supported: Message Batches, token counting, on-demand compaction, most context editing, and organizations with HIPAA readiness or Inference hooks turned on. At most 4
cache_controlbreakpoints per request, and there is no API to list, read or delete threads. - Streaming: the id arrives in
message_start, but you can only continue aftermessage_stop. After astop_reason: "refusal", do not continue: open a new thread without that turn.
The limit that weighs most is compliance: if your organization runs on zero data retention, this feature is off the table, because the conversation sits in the provider's memory for up to an hour. For everyone else running long-context agents, it is a few lines with the SDK helper, as long as the replay path is tested before you need it.
Sources
- Make long-running agents faster with message threads (Anthropic, November 2, 2026)
- Message threads documentation (Claude Platform Docs)
- Anthropic's Message Threads cut time to first token by 35 percent (The Decoder, November 3, 2026)
- Conversation state (OpenAI)