Rubric
Contents — domains, guide and mocks

Claude API mechanics

CCDV-F 2.316 min read · checked 21 September 2026

Task statementClaude API Mechanics (6.8%) — messages, tools, streaming, vision, thinking, caching, third-party vendor access, Messages API data patterns, batch API use, and realtime versus batch tradeoffs

Anatomy of a Messages request

headers first, then the prompt prefix in order

  1. Headersx-api-key, anthropic-version, content-type
  2. model · max_tokensboth required on every request
  3. toolsfirst part of the cacheable prefix
  4. systemrole, rules, long stable context
  5. messagesthe whole conversation, as content blocks
Read it top to bottom: this order is also the order the prompt prefix is assembled in, which is what makes caching predictable.

The request and the response

Three fields are required: model, messages and max_tokens. Everything else is optional — system, tools, tool_choice, temperature, stop_sequences, stream, thinking, metadata, service_tier. Three headers travel with every raw HTTP call: your API key, the API version, and the content type. The client SDKs set the version header for you and read the key from the ANTHROPIC_API_KEY environment variable.

The response is a message object: an id, the model that answered, role of assistant, a content array of blocks, a stop_reason, and usage. Usage is where cost and caching become visible — input_tokens, output_tokens, cache_creation_input_tokens and cache_read_input_tokens. Reading stop_reason correctly is the subject of task statement 4.1; here it is enough to know it exists and that tool_use means the model is waiting on you.

A minimal call, with the pieces namedpython
from anthropic import Anthropic

client = Anthropic()          # reads ANTHROPIC_API_KEY from the environment

resp = client.messages.create(
    model=MODEL_ID,           # pin this in configuration, not at the call site
    max_tokens=1024,          # required: the ceiling on output tokens
    system="You are a claims triage assistant.",
    messages=[{"role": "user", "content": "Summarise claim A-1042."}],
)

print(resp.stop_reason)       # end_turn, tool_use, max_tokens, ...
print(resp.usage.input_tokens, resp.usage.output_tokens)
print(resp.content[0].text)   # content is a list of blocks, not a string

Two habits follow from that snippet. Never treat content as a string: it is a list, and a single turn can hold thinking, text and a tool request together. And never hard-code the model identifier at the call site — 2.6 covers why it belongs in configuration.

Content blocks: the data patterns

The messages array is not plain text. Each message's content is a list of typed blocks, and the block type is what determines how Claude receives the data. Knowing which block goes where is the single most testable piece of Messages API mechanics.

BlockDirectionWhat it carries
textBothPlain text
imageYou sendbase64, url, or file source with a file_id
documentYou sendA PDF or text file, optionally with citations enabled
tool_useClaude returnsid, name, input — a request for you to run something
tool_resultYou send backtool_use_id matching the request, plus content and optional is_error
thinkingClaude returnsReasoning text with a signature

Images. Claude accepts JPEG, PNG, GIF and WebP, up to 8000 by 8000 pixels, with a base64 size limit of 10 MB on the Claude API (5 MB via Bedrock and Google Cloud). Token cost is geometric, not per-file: the image is divided into 28-by-28 pixel patches, so cost rises with area — roughly 1,296 tokens for a 1000-by-1000 image. Oversized images are downscaled automatically. Putting the image before the text performs best, and for multi-turn conversations the Files API is the better pattern: upload once, then reference file_id instead of re-encoding the same megabytes on every turn.

Tools. A tool definition is a name, a description and an input_schema in JSON Schema. tool_choice decides how freely Claude may use them: auto (default), any (must call something), a named tool, or none. When you return the result, tool_use_id must match the request, and a failure is reported with is_error rather than by inventing a plausible answer. Tool definitions are not free — they sit in the prefix and cost input tokens, plus a few hundred tokens of system overhead when tools is present at all. Tool design proper is domain 8; what matters here is the round-trip shape.

Streaming

Set stream: true and the response arrives as server-sent events instead of one body. The sequence is fixed: message_start carries the message shell with empty content; then, for each content block, a content_block_start, a run of content_block_delta events, and a content_block_stop; then one or more message_delta events; then message_stop. ping events may appear anywhere, and errors arrive as error events inside the stream.

The delta type tells you what is arriving: text_delta for text, thinking_delta and signature_delta for reasoning, and input_json_delta for a tool call's arguments. That last one catches people out — tool input arrives as fragments of JSON text, so you accumulate the partial_json strings and parse once, at content_block_stop. stop_reason and the final usage numbers appear on message_delta, not on message_start, which is why a streaming client cannot decide it is finished from the text alone.

The shape of a stream

Your client
Claude API
Step 1: Your client to Claude API: request with stream: true
Step 2: Claude API to Your client: message_start · empty content
Step 3: Claude API to Your client: content_block_start
Step 4: Claude API to Your client: deltas: text or partial_json
Step 5: Claude API to Your client: content_block_stop · parse now
Step 6: Claude API to Your client: message_delta · stop_reason, usage
Step 7: Claude API to Your client: message_stop
Notice where the two pieces of decision-making data live: tool arguments complete at content_block_stop, and stop_reason arrives on message_delta.

Streaming is also an operational requirement, not only a user-experience choice. The documentation puts a ten-minute ceiling on a request and tells you to stream or use batches for anything expected to run longer; a large max_tokens on a non-streaming request is the classic way to hit it. The SDKs provide accumulators — get_final_message() in Python, finalMessage() in TypeScript — so you can stream for reliability and still work with one complete message at the end.

Thinking

Thinking gives the model room to reason before answering, and the reasoning comes back as thinking blocks with a signature. Thinking tokens are billed as output tokens and count inside the context window. On current models the parameter is thinking with type of adaptive, and depth is steered by output_config.effort at low, medium or high — the model decides how much reasoning each input deserves.

One multi-turn detail matters for tool loops: whether previous thinking blocks are preserved when you send the conversation back differs by model, and where they are preserved they are billed as input tokens. Either way, you pass back what the API gave you rather than editing the assistant turn, and you keep history append-only.

Prompt caching

Caching stores the processed form of a prompt prefix so repeated requests skip re-processing it. You mark the end of the cacheable region with cache_control of type ephemeral on a block — at most four explicit breakpoints per request. The default lifetime is five minutes, refreshed on each hit, with a one-hour option at a higher write price. Cache writes cost more than ordinary input; cache reads cost a fraction of it.

The prefix is assembled in a fixed order — tools, then system, then messages — and a change at any level invalidates that level and everything after it. Hence the one rule worth memorising: put the breakpoint at the end of the last block that is identical on every request. A timestamp, a user name or a per-request question above the breakpoint means a miss every single time.

Where the breakpoint goes

Never hitspython

system=[
  {"type": "text",
   "text": POLICY_MANUAL},
  {"type": "text",
   "text": f"Now: {now()}",
   "cache_control":
     {"type": "ephemeral"}},
]

Hits every timepython

system=[
  {"type": "text",
   "text": POLICY_MANUAL,
   "cache_control":
     {"type": "ephemeral"}},
]
messages=[{"role": "user",
  "content": question}]
Same content, same order, one difference: whether anything that changes sits above the breakpoint. Check usage.cache_read_input_tokens to see which case you are in.

Two consequences are worth carrying into design. Caching has a minimum size — short prefixes are simply not cached, with no error — so verify by reading cache_creation_input_tokens and cache_read_input_tokens rather than assuming. And on most models cached reads do not count toward your input-tokens-per-minute rate limit, so a well-cached design buys throughput headroom as well as money.

Realtime or batch

The Message Batches API takes up to 100,000 requests in one submission (256 MB), processes them asynchronously at a 50% discount, and guarantees results within 24 hours — most batches finish in under an hour. Each request carries a custom_id; results come back as JSONL, streamed from a results URL, not in submission order, with a result type per line of succeeded, errored, canceled or expired. Only successes are billed.

Two paths for the same model

Realtime (Messages API)

  • A person or a caller is waiting on the answer
  • Stream for perceived speed; ten-minute ceiling per request
  • Full price; rate limits apply per minute
  • Work arrives one item at a time

Batch (Message Batches API)

  • Nobody waits; results within 24 hours
  • 50% discount; up to 100,000 requests per batch
  • No streaming; match results by custom_id
  • The whole workload is known up front
The question is never “which is better”. It is whether a person is waiting, and whether the work can be enumerated in advance.

Batches support the features you would expect — vision, tool use, system prompts, thinking, and prompt caching on a best-effort basis — but not stream: true, since results are collected as a file rather than pushed. A mixed design is common and correct: batch the overnight backlog, serve the live queue in realtime, and share the same prompts between them.

Third-party vendor access

Claude is also available through cloud providers — Amazon Bedrock, Google Cloud and Microsoft Foundry — and this appears on the exam because it changes integration mechanics, not model behaviour. The Messages request and response shape is the same. What changes is authentication, identifiers and feature coverage.

Claude APIAmazon Bedrock
Authenticationx-api-key headerAWS credentials or bearer token, IAM controlled
SDK clientAnthropicAnthropicBedrock, from the bedrock extra
Model identifiere.g. claude-sonnet-4-6Prefixed, e.g. anthropic.claude-sonnet-4-6, or an inference-profile ARN
ResidencyAnthropic-operatedGlobal endpoints, or regional endpoints at a premium
Feature coverageEverythingNo Message Batches, no Files API; explicit cache breakpoints only

The pattern to remember: a requirement expressed as “it must run in our cloud account” is satisfiable, but it removes some features and changes every identifier in your configuration. Check the feature list against your functional requirements before promising a migration — a design that depends on the Batches API cannot simply be repointed at Bedrock.

Traps the wrong answers are built from

Tempting but wrongDo this instead
Putting the cache breakpoint after per-request content such as a timestampPlace it at the end of the last block that is byte-identical on every request.
Parsing a tool call's arguments from streaming deltas as they arriveAccumulate partial_json and parse once at content_block_stop.
Re-encoding the same image on every turn of a conversationUpload once with the Files API and reference file_id.
Setting a very large max_tokens on a non-streaming requestStream, or use the Batches API, for anything that may run beyond the ten-minute ceiling.
Assuming batch results come back in submission orderMatch every result to its request by custom_id and handle errored and expired lines.
Promising a cloud-provider migration without checking feature coverageCompare the required features against that platform's list first — batches and Files are not everywhere.

You should now be able to

  • Assemble a Messages request correctly and read stop_reason and usage from the response.
  • Choose the right content block for text, images, documents and tool results, and match tool_use_id.
  • Consume a stream in order and know where stop_reason, usage and tool arguments appear.
  • Place cache_control breakpoints so the cache actually hits, and verify it from usage fields.
  • Decide between realtime and batch from whether a person is waiting and whether work is enumerable.
  • State what changes when Claude is accessed through a cloud provider instead of the Claude API.

Practice questions

Original questions written for this lesson, in the exam’s style. Answer first, then open the reasoning — every option is explained, including why the wrong ones are tempting.

  1. Question 1

    A support tool sends a 30,000-token knowledge base in the system prompt on every request, with a cache_control breakpoint on a final system block containing the current date and the agent's name.

    Why is cache_read_input_tokens always zero, and what fixes it?

    1. AThe knowledge base is too large to cache, so it must be split across several separate requests.
    2. BThe changing date is inside the cached prefix; move the breakpoint above it.
    3. CCaching requires the one-hour TTL for prompts this large; add "ttl": "1h".
    4. DTools must be defined for caching to apply; add at least one tool definition.
    Show answer and reasoning
    1. AIncorrect. Size is a minimum, not a maximum — 30,000 tokens is comfortably cacheable.
    2. BCorrect. The prefix runs from the start of the request to the breakpoint, so variable content inside it changes the prefix and forces a miss every time.
    3. CIncorrect. A longer TTL changes lifetime and write price, not whether a changing prefix matches.
    4. DIncorrect. Tools occupy the first part of the prefix but are not a precondition for caching.
  2. Question 2

    A compliance team must classify 60,000 archived chat transcripts against a policy. There is no deadline inside the working day, and the work is fully known in advance.

    Which approach best fits, and what must the implementation handle?

    1. ARealtime requests in a loop with retries, to see progress as it goes.
    2. BRealtime streaming requests in parallel threads, cancelling any that exceed ten minutes.
    3. CThe Message Batches API, matching results by custom_id and re-queuing errored lines.
    4. DThe Message Batches API with stream: true so results arrive as they complete.
    Show answer and reasoning
    1. AIncorrect. It works, but pays full price, consumes per-minute limits and gives no batch-level accounting.
    2. BIncorrect. Parallel streaming adds complexity and cost for a workload where nobody is waiting.
    3. CCorrect. The work is enumerable and nobody waits, so batch gives the discount; results arrive out of order, so custom_id matching and error handling are required.
    4. DIncorrect. Streaming is not supported in batches; results are collected and read from a results URL.
  3. Question 3

    A developer streams responses and parses tool arguments by running JSON decode on the text of each delta as it arrives. Intermittently the agent calls a tool with missing parameters.

    What is happening?

    1. AThe model is emitting invalid JSON; enable strict tool use to force valid arguments.
    2. BTool input streams as partial JSON fragments; the client must accumulate until content_block_stop.
    3. CParallel tool use is interleaving two calls; set disable_parallel_tool_use.
    4. DThe stream is dropping events; add a retry around the whole request.
    Show answer and reasoning
    1. AIncorrect. Strict tool use constrains the model's output, but the bug here is in the client's accumulation, not the model's JSON.
    2. BCorrect. input_json_delta carries pieces of a JSON string, so only the concatenation is valid JSON — parsing a fragment yields a truncated object.
    3. CIncorrect. Parallel calls arrive as separate indexed content blocks, so they do not merge into one another's arguments.
    4. DIncorrect. Nothing is lost — the fragments are arriving as designed and being parsed too early.
  4. Question 4

    A healthcare customer requires that inference run inside their own AWS account. The existing application uses the Claude API and relies on the Message Batches API for a nightly job, and uploads PDFs through the Files API.

    What should the team tell the customer?

    1. AThe migration is a base-URL change, since the Messages API shape is identical.
    2. BBedrock supports everything the Claude API does once the right IAM role is attached.
    3. CResidency is achievable, but the nightly batch and PDF uploads need redesign on that platform.
    4. DThey should keep the Claude API and encrypt requests, which satisfies residency.
    Show answer and reasoning
    1. AIncorrect. The message shape is identical, but identifiers, authentication and feature coverage all change.
    2. BIncorrect. IAM covers authentication; it does not add features the platform does not offer.
    3. CCorrect. Bedrock uses AWS credentials and prefixed model identifiers, and the Batches and Files APIs are not available there, so those two parts of the design must change.
    4. DIncorrect. Encryption in transit does not change where the request is processed, which is what the requirement is about.

Sources

Drafted with AI assistance and checked against the sources above; expert review is in progress. Spotted an error? Tell us and it gets fixed, dated and listed on how this is written.