Back to all posts

cat posts/claude-message-threads-foundry-faster-not-cheaper.md --category "Azure & Cloud" --views 10

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.

  • --author By Falak Mahmood
  • --date November 4, 2026
  • --read 14 min read
  • --views 10 views

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.

PropertyClaude message threadsClaude prompt cachingAzure OpenAI previous_response_id
What you send per turnNew messages plus one idFull conversationNew input plus one id
Input tokens billed per turnFull conversation, unchangedCache 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 effectAbout 35% lower median TTFT at 500K to 1M tokensLower TTFT on cached prefixNot documented
Server-side lifetime5 min expiry, deleted within 1 h, memory only5 min or 1 h TTL, refreshed on use30 days by default, deletable, or store: false
ZDRNot eligibleEligibleSeparate Azure arrangement
Edit or branch historyNew thread onlyFree, cache invalidates from the editChain from any stored response
Works with batchesNoYesN/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.

ConfigurationInput cost, 100 turnsBytes per request near the endTTFT
No caching, no thread22.5M × $4 = $90Roughly 1.5 MB of JSONBaseline
Caching every turn, no threadAbout 22.15M reads × $0.20 + 350K writes × $5 = about $6.20Roughly 1.5 MB of JSONLower, cached prefix
Caching every turn, with threadAbout $6.20, unchangedA few KBLowest, and steadier as context grows
Thread, no caching$90, unchangedA few KBLower 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 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%.

subscribe # the AI news that matters, minus the noise

Book a Call

Sources

Tags

Related posts