# Claude message threads in Foundry: faster, not cheaper

Claude message threads went into public beta on 2 November 2026, including on Microsoft Foundry: send the conversation once, then only new messages and an id, for about 35% lower time to first token on 500K to 1M token requests. Token charges and rate limits do not change, so caching remains the cost lever. The thread is a server-side copy of your conversation, held in memory for up to an hour and outside ZDR, which EU teams need to document.

- Published: 2026-11-04 · Category: Azure & Cloud · Tags: Claude, message threads, Microsoft Foundry, prompt caching, Azure OpenAI, Responses API, Opus 5.5, zero data retention, GDPR, molnpolicy, AI agents, latency
- Author: Technspire AB, Stockholm (https://technspire.com)
- Canonical: https://technspire.com/en/blog/claude-message-threads-foundry-faster-not-cheaper

On 2 November 2026 Anthropic put message threads into public beta on the Claude API, on Claude Platform on AWS, on Claude Models on Google Cloud and on Claude in Microsoft Foundry. The idea is simple: send the whole conversation once, then send only the new messages plus the id of the previous response. Anthropic says requests with 500K to 1M tokens of context see median time to first token fall by about 35%. The part that matters for a budget owner is the sentence next to it: standard token rates and existing rate limits apply. Threads change how many bytes cross the wire and how long you wait for the first token. They do not change the bill. For a Swedish or EU team running agents on Foundry, there is a second thing to read before switching it on: the thread is a server-side copy of your conversation, held by Anthropic, outside zero data retention.

## What a thread is

A message thread keeps a conversation on the server for a short time. Three request types cover the whole lifecycle.

- **Create.** Send the full conversation with `system` and `tools` as you do today, and add `"thread": {"type": "create"}`. The API stores the conversation, including Claude's reply, under the response id.
- **Continue.** Send only the messages since the previous response, and add `"thread": {"type": "continue", "previous_message_id": "..."}`. Leave `system` and `tools` out; sending either on a continue request, even as null, returns a 400.
- **Replay.** A thread expires 5 minutes after its last request and is deleted no more than 1 hour after its last use. If the API cannot continue it, you get a 404 with the code `thread_not_found`, and you send the full conversation again in a new create request.

Every request of a thread needs the beta header `message-threads-2026-08-12`. A thread is append-only, and each response id can be continued exactly once; continuing an older id returns `thread_already_continued`. There is no API to list, read or delete a thread. Your application stays the source of truth: no response tells you whether the API stored that turn, you only find out on the next continue request. Anthropic's docs say to build the replay path from the start, and the SDK thread helper does it for you, keeping the conversation in process memory and nowhere else.

Fields fall into three groups. Create-only fields are `system` and `tools`. Fixed fields must be sent on every request with identical values: `model`, `tool_choice`, `thinking`, `output_config`, `context_management`, the top-level `cache_control` and the set of beta headers. A differing value returns `thread_fingerprint_mismatch`. Free fields such as `max_tokens`, `stream` and `metadata` can change per turn. To change anything fixed, start a new thread.

## Three ways to carry state, side by side

Teams on Azure now have three mechanisms that look alike from a distance and do different jobs. Prompt caching cuts cost. Threads cut latency and payload. The Azure OpenAI Responses API's `previous_response_id` cuts client code. They are not substitutes for each other.

| Property | Claude message threads | Claude prompt caching | Azure OpenAI previous_response_id |
| --- | --- | --- | --- |
| What you send per turn | New messages plus one id | Full conversation | New input plus one id |
| Input tokens billed per turn | Full conversation, unchanged | Cache reads at 0.1x base (0.05x on Opus 5.5 and Sonnet 5.5, 0.025x on Fable 5.1) | Full chain billed as input on OpenAI's platform; Azure docs do not state otherwise |
| Latency effect | About 35% lower median TTFT at 500K to 1M tokens | Lower TTFT on cached prefix | Not documented |
| Server-side lifetime | 5 min expiry, deleted within 1 h, memory only | 5 min or 1 h TTL, refreshed on use | 30 days by default, deletable, or store: false |
| ZDR | Not eligible | Eligible | Separate Azure arrangement |
| Edit or branch history | New thread only | Free, cache invalidates from the edit | Chain from any stored response |
| Works with batches | No | Yes | N/A |

The two Claude mechanisms compose, and the docs are explicit that a thread does not cache anything for you. Send a top-level `cache_control` on every request of the thread and 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. A request with `thread` may carry at most 4 cache breakpoints, the top-level one counts as one, and breakpoints on `system` and `tools` from the create request count again on every continue request. One too many returns `thread_unsupported_request`.

## The cost math: threads move nothing

Take a coding agent on Claude Opus 5.5, hosted on Azure, Global Standard. Opus 5.5 is $4 per million input tokens, $5 per million for a 5-minute cache write and $0.20 per million for a cache read. The session runs 100 turns, context grows from 50K to 400K tokens, and the average request carries 225K tokens of context, so the session sends about 22.5 million input tokens in total. Output tokens are left out because none of the three mechanisms touches them.

| Configuration | Input cost, 100 turns | Bytes per request near the end | TTFT |
| --- | --- | --- | --- |
| No caching, no thread | 22.5M × $4 = $90 | Roughly 1.5 MB of JSON | Baseline |
| Caching every turn, no thread | About 22.15M reads × $0.20 + 350K writes × $5 = about $6.20 | Roughly 1.5 MB of JSON | Lower, cached prefix |
| Caching every turn, with thread | About $6.20, unchanged | A few KB | Lowest, and steadier as context grows |
| Thread, no caching | $90, unchanged | A few KB | Lower than baseline |

The bottom row is the trap. A team that reads "send only the new messages" as "pay only for the new messages" will switch threads on, watch the request size collapse, and see the invoice unchanged. The $84 saving in this example comes from caching, which the thread helper asks for only if you pass `cache_control` when you create it. The thread's contribution is the TTFT line and the 1.5 MB that no longer leaves your App Service or Container App on every turn.

One timing detail affects both mechanisms the same way. A 5-minute cache lifetime is measured from the start of the request that wrote or read it, and a thread expires 5 minutes after its last request. An agent that spends six minutes running a tool between turns loses the cache and the thread together. For that workload use the 1-hour cache, at $8 per million for the write on Opus 5.5, and accept that the thread will replay.

## Shipping it on Foundry

Anthropic lists Microsoft Foundry as a beta platform for threads with no hosting caveat, and threads do not appear in the list of features that only work on Anthropic-hosted deployments. Microsoft's own Foundry capability tables are dated 21 September 2026 and do not mention threads at all yet. Treat that as documentation lag, verify against your own deployment, and expect a plain 400 or a `thread_unsupported_request` if a given deployment type is behind.

The request shape is the standard one against the Foundry endpoint. The Foundry clients in the Anthropic SDKs are the same client classes with a different base URL and Entra ID support, so the thread helper is available; the explicit form below shows what goes over the wire.

```
import AnthropicFoundry from "@anthropic-ai/foundry-sdk";
import { DefaultAzureCredential, getBearerTokenProvider } from "@azure/identity";

const client = new AnthropicFoundry({
  resource: "tsp-foundry-swc",   // https://tsp-foundry-swc.services.ai.azure.com/anthropic
  azureADTokenProvider: getBearerTokenProvider(
    new DefaultAzureCredential(), "https://ai.azure.com/.default"),
});

const fixed = {
  model: "claude-opus-5-5",            // deployment name
  max_tokens: 8000,
  thinking: { type: "adaptive" },
  output_config: { effort: "medium" },
  cache_control: { type: "ephemeral" }, // fixed field: same value every turn
  betas: ["message-threads-2026-08-12"],
};

// Turn 1: full conversation, system and tools, create the thread
const first = await client.beta.messages.create({
  ...fixed,
  system: SYSTEM_PROMPT,
  tools: TOOLS,
  messages: history,
  thread: { type: "create" },
});

// Turn 2: only the tool results, no system, no tools
const second = await client.beta.messages.create({
  ...fixed,
  messages: [{ role: "user", content: toolResultsFor(first) }],
  thread: { type: "continue", previous_message_id: first.id },
});
```

Four Foundry-specific points follow from the docs.

- **Fallbacks are client-side on Foundry, so the thread ends with them.** The server-side `fallbacks` parameter is not supported on Foundry. When your own retry logic reroutes a refused turn to another deployment, that is a new model, and a thread keeps one model. Start a new thread on the fallback deployment from your copy of the conversation, and do not continue a thread after `stop_reason: "refusal"`.
- **One principal per thread.** A continue request from a different user, service account or workspace returns `thread_not_found`. Keep one managed identity or one API key for the whole thread. Entra ID tokens rotate hourly for the same principal, which should be fine, but test a thread that spans a token refresh before relying on it.
- **Token counting excludes threads.** The Foundry Token Count API returns a 400 if the request includes `thread`. Count the full conversation with `system` and `tools` instead, which is also what your replay path needs anyway.
- **Compaction is manual.** Compaction on demand and most context editing are unavailable with threads. When the conversation needs summarising, write the summary in your code and start a new thread from it.

For streaming, the response id arrives in `message_start`, but continue from it only after `message_stop`. If a continue stream drops, resend the same continue request; if that returns `thread_already_continued` or `thread_continue_in_flight`, replay. Replaying is always safe, which is why your conversation store, whether Cosmos DB, Redis or a durable orchestration state, must hold the full history and not only the latest id.

## The Swedish and EU angle: where the thread lives

Threads add a new category to a data flow that regulated Swedish organisations have already mapped once for Claude on Foundry. Anthropic's statement is precise: a thread's contents, meaning the conversation, system prompt and tools, are held in memory, encrypted under a server-managed key, never written to durable storage, and deleted no more than 1 hour after the thread's last use. Message threads are not ZDR eligible and not HIPAA eligible, and organisations with HIPAA readiness enabled are rejected outright with `thread_unsupported_request`. ZDR organisations are not blocked; their thread data simply sits outside the ZDR scope for up to an hour. If your DPIA for Claude on Foundry says "no conversation content is retained by Anthropic beyond the request", that sentence is no longer true once `thread` is in the request.

Who holds it, and where, follows from Foundry's hosting model rather than from the thread feature. On both hosting options Anthropic is the seller, the operator and the independent data processor under its own Data Processing Addendum. For deployments hosted on Azure, Anthropic's note says prompts and completions remain within Azure, with only usage metadata and safety-flagged content leaving for Anthropic. The in-memory thread is conversation content, so the reasonable reading is that it sits inside the Anthropic-operated service on Azure infrastructure, but neither company's documentation says that in so many words. For deployments hosted on Anthropic infrastructure, Microsoft's wording is that data might be processed outside Azure, including outside the selected Azure geography. Ask your account team for the thread storage location in writing before you put it in a records-of-processing entry.

Geography does not get better with threads. Microsoft's region table lists every Claude model in Sweden Central, which keeps your Foundry resource and its metadata in Sweden, but the only deployment types are Global Standard, which processes anywhere Azure runs, and a US Data Zone for the Azure-hosted Opus, Sonnet and Haiku models. The Europe tab of the Data Zone table still reads "Not available", as it did when we covered the [Fable 5.1 launch on Foundry](/en/blog/claude-fable-5-1-foundry-cache-math-eu-caveats) in September, and Anthropic's data residency page offers only "us" and "global" as inference geos. A thread cached in a Global Standard deployment is a thread cached wherever the request landed.

For public-sector buyers there is a design principle hiding in the replay rule. The government's cloud policy of 28 May 2026 says agencies, municipalities and regions should choose solutions that make it possible to move data and services without unnecessary obstacles, and names open standards, clear contracts and a plan for exit as the tools against lock-in. Threads score well on that test precisely because they are best-effort: the API never promises to keep the conversation, so a correct implementation can switch to a full create request, or to a different model or platform, at any turn without losing anything. The conversation store you build for replay is your exit plan. A team that skips it, and lets the SDK helper's in-memory copy be the only copy, has built the dependency the policy warns about, with a 5-minute fuse on it.

Two retention rules stay exactly as they were. Covered Models, which include Fable 5.1 and Mythos 5.1, still require 30-day retention of prompts and outputs at Anthropic regardless of threads. And Azure OpenAI's Responses API still stores response objects for 30 days by default unless you pass `store: false`, which is a far longer server-side footprint than a thread's single hour.

## Decision guide

- **Switch threads on** for long agent loops, computer-use sessions and document-heavy conversations above roughly 100K tokens, where TTFT is visible to a user or gates the next tool call, and where you already run the conversation through a store you control.
- **Leave them off** for short chats, for anything that goes through Message Batches, for HIPAA organisations, for workloads that rely on compaction on demand or context editing, and for any pipeline that cannot reconstruct the full conversation on demand.
- **Do caching first.** If you have not yet added `cache_control`, that is where the money is. Threads are the second step, and the helper takes the same parameter.
- **Price the replay.** A replay is a full create request. For a 400K-token conversation on Opus 5.5 with caching, that is a cache read of about $0.08; without caching it is $1.60. Design for replays to happen, because tool runs longer than five minutes guarantee them.
- **Update the DPIA** with the in-memory copy, its 1-hour ceiling, and its exclusion from ZDR, and record whether the deployment is Azure-hosted or Anthropic-hosted.

## Checklist

- **1. Add the beta header** `message-threads-2026-08-12` to every request of a thread, or let the SDK helper add it.
- **2. Pass a top-level `cache_control`** on every request, with the same value, and keep breakpoints at 4 or fewer.
- **3. Persist the full conversation** in your own store before you rely on any thread id. Store the latest id next to it.
- **4. Handle the four error codes**: replay on `thread_not_found`, `thread_already_continued` and `thread_continue_in_flight`; fix the request on `thread_fingerprint_mismatch`.
- **5. Start a new thread after a refusal** and after any client-side fallback to another deployment.
- **6. Keep one principal per thread** and test across an Entra ID token refresh.
- **7. Watch the cost dashboard, not the request size.** Confirm that input token totals and cache-read ratios in Azure Cost Management look the same before and after.
- **8. Record the data-flow change** in the DPIA and the records of processing, and ask for the thread storage location in writing.

## Conclusion

Message threads are a good feature with a misleading silhouette. They look like a cost control and are a latency control. On Foundry they arrive with the same hosting, residency and retention rules that already applied to Claude there, plus one new short-lived server-side copy of the conversation that your compliance documents have to mention. Add caching first, build the replay path, and then take the 35%.

## Sources

- [Anthropic: Introducing message threads (2 November 2026)](https://claude.com/resources/articles/message-threads)
- [Claude Platform docs: Message threads (beta header, fixed fields, errors, data retention, platform availability)](https://platform.claude.com/docs/en/build-with-claude/message-threads)
- [Claude Platform docs: Prompt caching (multipliers, TTL measurement, minimum cacheable length)](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)
- [Claude Platform docs: Pricing (Opus 5.5 rates, cache read multipliers, Claude in Microsoft Foundry CCU billing)](https://platform.claude.com/docs/en/about-claude/pricing)
- [Claude Platform docs: Claude in Microsoft Foundry (hosting options, unsupported features, data note)](https://platform.claude.com/docs/en/build-with-claude/claude-in-microsoft-foundry)
- [Claude Platform docs: Data residency (inference_geo values, Foundry US Data Zone equivalence)](https://platform.claude.com/docs/en/manage-claude/data-residency)
- [Claude Platform docs: API and data retention (ZDR scope, Covered Models)](https://platform.claude.com/docs/en/manage-claude/api-and-data-retention)
- [Microsoft Learn: Claude models in Microsoft Foundry (capability tables, dated 21 September 2026)](https://learn.microsoft.com/en-us/azure/foundry/foundry-models/concepts/claude-models)
- [Microsoft Learn: Compare hosting options for Claude models in Microsoft Foundry](https://learn.microsoft.com/en-us/azure/foundry/foundry-models/concepts/claude-models-hosting-comparison)
- [Microsoft Learn: Data, privacy, and security for Anthropic Claude models in Microsoft Foundry](https://learn.microsoft.com/en-us/azure/foundry/responsible-ai/claude-models/data-privacy)
- [Microsoft Learn: Foundry Models from partners and community (region availability by deployment type)](https://learn.microsoft.com/en-us/azure/foundry/foundry-models/concepts/models-from-partners)
- [Microsoft Learn: Azure OpenAI Responses API (previous_response_id, 30-day retention, store parameter)](https://learn.microsoft.com/en-us/azure/foundry/openai/how-to/responses)
- [OpenAI: Conversation state (input token billing across a previous_response_id chain)](https://developers.openai.com/api/docs/guides/conversation-state)
- [Regeringen: Ny molnpolicy ska bidra till ökad digital suveränitet i offentlig förvaltning (28 May 2026)](https://www.regeringen.se/pressmeddelanden/2026/05/ny-molnpolicy-ska-bidra-till-okad-digital-suveranitet-i-offentlig-forvaltning/)
- [Technspire: Claude Fable 5.1 in Foundry: cache math and the EU caveats](https://technspire.com/en/blog/claude-fable-5-1-foundry-cache-math-eu-caveats)
- [Technspire: Spotify cut Claude Code tokens 90%: copy the pattern](https://technspire.com/en/blog/spotify-cut-claude-code-tokens-90-copy-the-pattern)

---

Technspire AB builds AI agents, Azure OpenAI solutions, and production web platforms for Swedish and EU enterprises. Book a call: https://calendly.com/technspire · hello@technspire.com · More articles: https://technspire.com/en/blog · Site overview for agents: https://technspire.com/llms.txt
