Skip to content
Domain 2Task 2.3

Claude API Mechanics

Learn this interactively

What You Need to Know

The Messages API is the interface that an application uses to send requests to Claude. A request names the model, sets the maximum reply length and contains the conversation so far. The response holds content, a list of typed content blocks: text, tool_use or thinking. It also holds stop_reason, which says why the model stopped generating, and usage, which holds the token counts.

This lesson uses one made-up example throughout: a travel booking website with a help chat. Customers ask about baggage rules, send photos and check their bookings. Each customer turn starts a Messages API request.

The Request and the Response

A request needs exactly three parameters: model, max_tokens and messages. Everything else is optional. system is a top-level parameter. On most current models, a system-role message can also appear later in messages, but never as the first entry. The messages array alternates user and assistant turns. The API merges consecutive messages that have the same role.

The API is stateless: by default it holds no conversation. As of November 2026, a beta called message threads can keep a conversation on the server for a few minutes. On every turn, the application sends again the transcript that it wants the model to see. If the travel site's chat sent only the newest question, Claude would answer without the history. It would not know about the flight that the customer named two turns earlier.

python
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    system="You answer customer questions for a travel booking website.",
    messages=[{"role": "user", "content": customer_question}],
)

print(response.stop_reason)
print(response.usage.input_tokens, response.usage.output_tokens)
print(response.usage.cache_creation_input_tokens, response.usage.cache_read_input_tokens)

The documented stop_reason values are:

  • end_turn: a natural finish
  • max_tokens: the reply reached the cap
  • stop_sequence: the output matched a configured stop sequence
  • tool_use: the model wants a tool run
  • pause_turn
  • refusal
  • model_context_window_exceeded: the context window filled

Read stop_reason before the content. With it, you can diagnose a truncation instead of blaming the model for it. When a travel site reply ends mid-sentence, the field shows whether the reply reached the max_tokens cap. In usage, total input is the sum of input_tokens, cache_creation_input_tokens and cache_read_input_tokens.

A request sends data as content blocks: text, image or document blocks. With Files API references, you upload a file once and reference it many times. The travel site could upload its booking terms once and reference them from every chat.

Tools at the Wire Level

A tool definition contains name, description and a JSON Schema input_schema. Suppose the travel site defines a tool that finds a booking. To call it, the model stops with stop_reason tool_use. The model also emits a tool_use block that holds an id, the tool name and the parsed input.

The caller, never Anthropic, runs a client tool. The travel site's own code finds the booking. Then the code sends a user turn that holds a tool_result block, and the tool_use_id of that block matches that id. The matching id links the result to the call. The handler below shows that exchange of tool call and result:

python
tools = [{
    "name": "look_up_booking",
    "description": "Look up a booking record by its booking reference.",
    "input_schema": {
        "type": "object",
        "properties": {"booking_reference": {"type": "string"}},
        "required": ["booking_reference"],
    },
}]

response = client.messages.create(
    model="claude-sonnet-5-5", max_tokens=1024, tools=tools, messages=messages,
)

if response.stop_reason == "tool_use":
    block = next(b for b in response.content if b.type == "tool_use")
    result = look_up_booking(**block.input)  # your code runs the tool
    messages.append({"role": "assistant", "content": response.content})
    messages.append({"role": "user", "content": [
        {"type": "tool_result", "tool_use_id": block.id, "content": result},
    ]})

tool_choice controls the model's tool decision. Its values are auto, any, tool (forcing a named tool) and none. Whether you can force a tool depends on the model. As of 14 November 2026, Claude Fable 5.2, Mythos 5.2, Opus 5.5, Sonnet 5.5, Fable 5.1 and Mythos 5.1 reject any and tool with a 400 error. Manual extended thinking rejects both on any model. For those cases, the documented route is auto with strict tool use.

Server tools such as web search reverse who runs the tool. Anthropic runs them, and the results arrive in the same response.

Streaming

With stream: true, the response arrives as server-sent events (SSE, a web standard for a stream of events from a server) in a documented order:

  1. message_start
  2. for each content block, a content_block_start, one or more content_block_delta events and a content_block_stop
  3. message_delta, with top-level changes and cumulative usage
  4. a final message_stop

ping events can arrive throughout.

typescript
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const stream = await client.messages.create({
  model: "claude-sonnet-5-5",
  max_tokens: 2048,
  messages: [{ role: "user", content: "Summarise these booking terms..." }],
  stream: true,
});

for await (const event of stream) {
  console.log(event.type);
  // message_start, content_block_start, content_block_delta,
  // content_block_stop, message_delta, message_stop, ping
}

Each delta has a type:

  • text_delta for text
  • input_json_delta for tool-call arguments: accumulate the partial JSON, then parse it at content_block_stop
  • thinking_delta, plus a closing signature_delta, for thinking blocks

Errors can also arrive mid-stream, as error events after the 200 response. A stream consumer therefore handles failure in two places: at the request, and inside the event stream.

Streaming changes the time to the first token. It does not change total cost or total generation time. So streaming is the fix when users wait and watch a loading indicator, as the travel site's chat customers do. For a slow batch job, streaming is irrelevant.

Vision

A request carries images as image content blocks. These blocks have three source types: base64 embedded bytes, a url reference, or a file id from the Files API. The Files API has left beta, so a request needs no beta header. As of September 2026, the legacy files-api-2025-04-14 header still works but only keeps the old beta response shapes.

Supported media types are JPEG, PNG, GIF and WebP. As of October 2026, each image can be up to 8000x8000 pixels and 10 MB on the Claude API and Claude Models on Google Cloud (Google managed), or 5 MB on Bedrock. The same October 2026 limits allow 100 images per request on 200k-context models and 600 on other models.

Claude reads the image in context, so the architecture needs no separate OCR (text recognition) service. The travel site's chat puts a customer's photo of a damaged suitcase directly into the request as an image block.

Image cost depends on patches: roughly one visual token per 28x28-pixel patch. Fewer pixels mean fewer patches, so if you resize images before you send them, you control both cost and latency. The domain quick reference lists the dated tier figures for vision.

Thinking

Thinking parameters depend on the model generation. Current models use thinking.type adaptive, and output_config.effort controls the depth. The older extended-thinking shape, type enabled with budget_tokens, is for models that predate adaptive thinking. The 4.6 generation still accepts it, but it is deprecated. From 4.7 onward, the API rejects it with a 400 invalid_request_error. Whether type disabled works depends on the model. Some current models keep thinking always on and return a 400 for disabled. Others accept it, some only at effort high or below. Check the per-model table in Troubleshooting thinking before you send it.

Thinking arrives as thinking content blocks before the text. Each block carries a signature. The display setting controls whether the response returns summarised thinking text or an empty block.

In multi-turn tool use, include thinking and redacted_thinking blocks in later requests exactly as you received them. If you edit, reorder or drop some of the blocks in the latest assistant turn, the API returns a 400. The API can also reject a block's signature because something earlier in the conversation changed. One documented fix is to strip that block and every later thinking and redacted_thinking block, then retry. The other is a beta setting: set thinking.block_binding.prefix_mismatch_behavior to "drop_block". With thinking on, the travel site's code appends the assistant turn unchanged before the tool_result turn.

Prompt Caching Mechanics

Prompt caching works by hashing the prefix, which is the start of the request up to a marked point. A cache_control marker of type ephemeral tells the API to cache everything up to that point. A request can set up to 4 explicit breakpoints (points marked with cache_control), or use the newer automatic top-level marker. A later request gets a cache hit only if its prefix is 100% identical. The API evaluates the prefix in a fixed hierarchy: tools, then system, then messages.

python
response = client.messages.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    system=[{
        "type": "text",
        "text": HOTEL_CATALOGUE,  # large, stable prefix
        "cache_control": {"type": "ephemeral"},
    }],
    messages=[{"role": "user", "content": customer_question}],  # volatile, last
)

The hash covers the exact prefix, so any changed byte before the breakpoint causes a cache miss. The design rule is therefore: stable content first, changing content last. The travel site caches its hotel catalogue in the system prompt and puts each customer question after it.

A change at one level of the hierarchy invalidates that level and every level after it. A change to tools invalidates everything. A change to system invalidates the system and message caches. If the travel site edited the booking tool's definition, it would lose every cached prefix.

Cache entries live 5 minutes by default, refreshed on use, or an hour with ttl set to "1h". The API silently does not cache a prompt below the per-model minimum cacheable length. The usage cache fields show zeroes for that prompt.

Batch Versus Realtime

The Message Batches API processes requests asynchronously at a 50% discount on all usage. A batch holds up to 100,000 requests or 256 MB, whichever is reached first. Every batched request needs max_tokens of at least 1.

Results become available when every request finishes or at the 24-hour mark, whichever comes first. Requests unfinished at 24 hours expire unbilled. Each result is succeeded, errored, canceled or expired. The results stream from a results_url that lives 29 days.

Most batches complete within an hour, but this is typical behaviour, not a guarantee. So work that tolerates latency, and where cost is the main concern, belongs in batch. Anything interactive stays realtime. So does any job whose hard deadline is inside the completion window. If throughput is the issue, use bounded client-side concurrency, which limits how many requests your code runs at the same time. The travel site's rewrite of every hotel description suits a batch. Its chat stays realtime.

Vendor Surfaces

One model family is reachable through several platforms. What changes for the developer is always the same short list:

  • authentication
  • endpoint
  • model-ID format
  • feature parity (whether a platform has the same features)
  • release timing

The request and response shape never changes: it is the Messages API everywhere.

Claude in Amazon Bedrock exposes the Messages API on a Bedrock endpoint. It uses SigV4 auth (the AWS method of signing requests) and anthropic.-prefixed model IDs. The legacy Bedrock path uses Converse/InvokeModel.

Claude Platform on AWS is a different kind of platform. Anthropic operates the platform and the full Claude API surface. That surface includes beta headers and first-party model IDs, and features typically arrive the same day. AWS provides authentication and Marketplace billing.

Claude Models on Google Cloud (Google managed) uses @date-suffixed IDs for dated pre-4.6 snapshots. Its current-generation IDs match the first-party format. Microsoft Foundry follows the first-party model lifecycle.

Feature parity (whether a platform has the same features) is the recurring caveat on the partner-operated platforms. Bedrock and Google Cloud (Google managed) support the core Messages API, caching, thinking and tool use. They do not carry the Batches API, the Files API or most of Anthropic's server tools. As of September 2026, Google Cloud (Google managed) carries web search and Bedrock carries none. On both, images arrive as base64 only. A travel site chat on Bedrock would send photos as base64 and lose access to the Batches API.

The Error Surface

Each status maps to an exact error type:

StatusError type
400invalid_request_error
401authentication_error
402billing_error
403permission_error
404not_found_error
409conflict_error
413request_too_large
429rate_limit_error
500api_error
504timeout_error
529overloaded_error

The API enforces rate limits with a token bucket (an allowance that refills continuously up to the limit) across requests per minute (RPM), input tokens per minute (ITPM) and output tokens per minute (OTPM). A rate-limit 429 names the exceeded limit and carries retry-after. The anthropic-ratelimit-* headers continuously expose limit, remaining and reset.

By default, the official SDKs retry transient failures (connection errors, 429s, 5xx) twice. They use exponential backoff and honour retry-after. A 529 means overload: reduce the request rate instead of sending more requests. Every error body carries a request_id for support.

As of September 2026, four rows need more explanation than the table gives:

  • A 409 means resolve the conflict, then retry.
  • A 504 on a long-running request suggests that you use streaming or the Message Batches API.
  • The tier's monthly spend cap returns a 429 with no retry-after and error.details.error_code enforced_spend_limit_reached. No retry clears it until access resumes.
  • A spend limit you set returns a 400. Limits on the Claude Code workspace can return a 429 instead.

For the travel site's chat, a 529 means the API is overloaded, so reduce the request rate. A 429 that carries enforced_spend_limit_reached means the travel site reached the monthly spend cap. No retry clears it until access resumes.

In the exam

Questions test exact parameter names, exact stop_reason strings and exact error types. The wrong options are invented values that are close to the real ones and look plausible. If you know the documented values, you can spot the invented one. Thinking is a common topic for wrong options that mix parameter names from different model generations. A question can test whether you recognise which platform a model string belongs to. The exam does not test enterprise platform strategy. It tests how an application connects to the API.

Domain 2 covers these exact request and response shapes. Domain 1 covers the loop that drives repeated calls, and Domain 8 covers how to describe tools well. Domain 5 covers when a task warrants thinking. Domain 5 also covers the write premiums and read discounts of caching, and when caching saves money. Here, the tested skill is to make the cache hit at all. Domain 4 covers how to find which layer of a failing system broke. This domain covers the handling mechanics.

Current-State Notes

Current state (checked 29 October 2026)

Two techniques from the time of the exam guide fail on current models. Claude 4.6 and later reject assistant-message prefill with a 400. Under API version 2026-10-21, a request that sends temperature, top_p or top_k at any value returns a 400 on every model. Under the older 2023-06-01 version, non-default values return a 400 on Claude 4.7 and later. Structured outputs and system-prompt instruction are the current ways to shape output. Where the guide covers a topic, the right answers follow the guide. The runnable code stays correct for current models. That is why none of the code on this page uses either technique.

Exam Traps

Exam Trap

Accepting an invented parameter or value because it sounds like the documented ones

Exactly three parameters are required: model, max_tokens and messages. tool_choice takes auto, any, tool and none; as of October 2026, ephemeral is the only cache_control type. Check any plausible-sounding extra field or value against the documented list.

Exam Trap

Attributing client tool execution to Anthropic's servers

The caller executes client tools and returns a tool_result block with the matching tool_use_id. Server tools such as web search are the documented exception, running on Anthropic infrastructure with results in the same response.

Exam Trap

Treating the typical under-an-hour batch completion as a guarantee that a deadline can depend on

Most batches finish within the hour, but only the 24-hour window is guaranteed, and requests unfinished at 24 hours expire unbilled. A hard deadline inside that window needs realtime calls under bounded concurrency.

Exam Trap

Guessing why generation stopped from a cut-off reply alone

Different stop_reason values need different fixes. max_tokens means the output cap was reached: raise it or ask for less. model_context_window_exceeded means the context window filled: treat the reply as truncated. Read stop_reason first.

Practice Scenario

A helpdesk software company summarises support tickets with the Messages API. Summaries intermittently arrive cut off mid-sentence. Inspecting a failing response shows usage.output_tokens exactly equal to the request's max_tokens value. What does the response's stop_reason read, and what fixes it?

Build Exercise

Build Exercise

Use Every Mechanism Once

Difficulty
45 minutes

What you'll learn

  • How to read stop_reason and usage instead of guessing from symptoms
  • How the documented server-sent event (SSE) sequence arrives in practice
  • How a cache breakpoint turns creation tokens into read tokens
  • How the tool_use / tool_result blocks go from the API to your code and back
  • How batch results stream back with per-request result types
  1. Write a script (Python or TypeScript SDK) that sends a Messages request and prints stop_reason and the full usage object; run it once normally and once with max_tokens set absurdly low

    Why: Producing the max_tokens stop on purpose means you see what a truncated reply looks like, in a test that you control, rather than during an incident.

    You should see: end_turn on the first run; max_tokens on the second, with output_tokens equal to your cap.

  2. Re-run with streaming enabled and log every SSE event type in arrival order

    Why: The documented event sequence is a fact that the exam tests, and watching it arrive teaches it better than memorising it.

    You should see: message_start, then content_block_start, deltas and content_block_stop per block, then message_delta and message_stop, possibly with ping events interspersed.

  3. Place a cache_control breakpoint after a large stable system prefix, call twice within five minutes, then change one early byte and call again

    Why: Watching cache_creation_input_tokens become cache_read_input_tokens, then vanish on a one-byte change, makes the identical-prefix rule clear from direct experience.

    You should see: Creation tokens on call one, read tokens on call two, and a full re-write on call three.

  4. Define one client tool with an input_schema, trigger it, execute the call yourself, and return a tool_result with the matching tool_use_id

    Why: Doing one full tool call and result shows who executes what and which ids must match.

    You should see: stop_reason tool_use, your function running locally, and a final text response that uses the result.

  5. Submit a five-request Message Batch, poll its status, stream the results from results_url, then give one request an invalid model name

    Why: Batch result types and the error surface are both facts that the exam tests, and one small batch exercises them together.

    You should see: succeeded results matched by custom_id, one errored result, and a documented error shape with a request_id.

Sources