Anthropic Message Threads
Production setup: use
https://api.modelgo.comfor the domestic gateway orhttps://api.modelgo.aifor the international gateway, with an API key from that environment. Examples below use the international production gateway.
Message Threads is an optional extension to Anthropic Messages on POST /v1/messages. The ModelGo gateway owns the short-lived thread: after authentication, it reconstructs the full conversation and sends a normal stateless request to the supplier. The supplier receives neither thread nor this feature's beta flag. Native supplier threads are not required.
Client uploads become smaller. The supplier still receives the complete history; input tokens are measured against that full context and actual cache usage. Threads do not automatically enable prompt caching or guarantee lower model charges or time to first token.
Official SDKs
These examples were verified with Python anthropic==2.4.0 (Python 3.10+) and TypeScript @anthropic-ai/sdk@1.4.0. The helper adds anthropic-beta: message-threads-2026-08-12 automatically.
The model name is illustrative. Replace it with a model that your API key is authorized to use and that has valid pricing configured in the current environment. The example does not imply that every API key can use this Claude model.
import os
import anthropic
client = anthropic.Anthropic(
api_key=os.environ["MODELGO_API_KEY"],
base_url="https://api.modelgo.ai", # No /v1 suffix
)
thread = client.beta.messages.thread(
model="claude-haiku-4.5", # Your API key must allow this model
max_tokens=256,
system="Keep replies short and remember the user marker.",
)
thread.send({"role": "user", "content": "Remember ALPHA."})
reply = thread.send({"role": "user", "content": "What was the marker?"})
print(reply.content)
with thread.stream({"role": "user", "content": "Repeat it."}) as stream:
final = stream.get_final_message()import Anthropic from '@anthropic-ai/sdk';
const client = new Anthropic({
apiKey: process.env.MODELGO_API_KEY,
baseURL: 'https://api.modelgo.ai',
});
const thread = client.beta.messages.thread({
model: 'claude-haiku-4.5', max_tokens: 256,
system: 'Keep replies short and remember the user marker.',
});
await thread.send({ role: 'user', content: 'Remember ALPHA.' });
const reply = await thread.send({ role: 'user', content: 'What was the marker?' });
const final = await thread.stream({ role: 'user', content: 'Repeat it.' }).finalMessage();Constructing a helper sends nothing. The first send() creates a thread; later send() / stream() calls upload only new messages. The helper keeps the full history locally.
Raw requests and constraints
Send the beta header above on every request, with the usual x-api-key authentication. Start with the complete conversation, system, tools, and "thread":{"type":"create"}. Continue from the previous response's id:
{
"model": "claude-haiku-4.5",
"max_tokens": 256,
"thread": {"type": "continue", "previous_message_id": "msg_previous"},
"messages": [{"role": "user", "content": "The next question"}]
}- Omit
system/toolson a continuation. Do not resend earlier messages or the previous assistant reply. Sendtool_resultin a newusermessage; resumepause_turnwith an emptymessageslist. - Each response
idmay be continued once. Use the latest response, sequentially. For streaming, wait formessage_stop. To edit history or branch, create a new thread with the full history. - Fixed fields, including
model,thinking,tool_choice,output_config, top-levelcache_control, and the beta set, must remain unchanged. The SDK helper manages these fields; changes require a new create request. Idempotency-Keyand/v1/messages/count_tokenscannot be combined with threads; send the full context when counting tokens. Compaction and context-management combinations that edit history are currently unsupported.
Expiry and recovery
Threads are best effort. Each stored response can be continued for at most five minutes, and capacity limits or storage failures may make it unavailable sooner. This is not durable conversation storage. Your application must keep the complete history, including across process restarts. Thread content is encrypted in shared storage, but this feature is not zero data retention (ZDR).
On thread_not_found, create a new thread with the complete history; the official SDK helper replays it automatically. The helper throws on thread_unsupported_request by default. Python unsupported_request_behavior="continue_unthreaded" or TypeScript unsupportedRequestBehavior: 'continue_unthreaded' retries that turn and sends all subsequent turns with the full history and no thread. After this fallback, the gateway no longer retains threads for those stateless requests.
Thread errors
Thread errors use the Anthropic envelope. The recovery discriminator is error.details.error_code:
{
"type": "error",
"error": {
"type": "not_found_error",
"message": "thread_not_found",
"details": {"error_code": "thread_not_found"}
}
}| HTTP | Recovery code | Meaning |
|---|---|---|
| 404 | thread_not_found | Missing, expired, or owned by another identity; create with the full history |
| 400 | thread_fingerprint_mismatch | A fixed field changed; correct it or create a new thread |
| 400 | thread_already_continued | The response was already continued; use the latest response or replay the full history |
| 400 | thread_continue_in_flight | Execution is in progress or its dispatch outcome is uncertain; do not blindly resubmit |
| 400 | thread_unsupported_request | Disabled feature, unsupported combination, capacity limit, or unavailable storage; a full-history stateless request is an option |
The SDK also replays a continuation under a new create request after thread_already_continued / thread_continue_in_flight. This is a new request; it does not replace reconciling an uncertain execution outcome.
Reference: Anthropic Message Threads. The supplier and billing boundaries described above are specific to ModelGo.