Anthropic Message Threads

Production setup: use https://api.modelgo.com for the domestic gateway or https://api.modelgo.ai for 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.

python
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()
ts
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:

json
{
  "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 / tools on a continuation. Do not resend earlier messages or the previous assistant reply. Send tool_result in a new user message; resume pause_turn with an empty messages list.
  • Each response id may be continued once. Use the latest response, sequentially. For streaming, wait for message_stop. To edit history or branch, create a new thread with the full history.
  • Fixed fields, including model, thinking, tool_choice, output_config, top-level cache_control, and the beta set, must remain unchanged. The SDK helper manages these fields; changes require a new create request.
  • Idempotency-Key and /v1/messages/count_tokens cannot 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:

json
{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "thread_not_found",
    "details": {"error_code": "thread_not_found"}
  }
}
HTTPRecovery codeMeaning
404thread_not_foundMissing, expired, or owned by another identity; create with the full history
400thread_fingerprint_mismatchA fixed field changed; correct it or create a new thread
400thread_already_continuedThe response was already continued; use the latest response or replay the full history
400thread_continue_in_flightExecution is in progress or its dispatch outcome is uncertain; do not blindly resubmit
400thread_unsupported_requestDisabled 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.