CCDV-F · module 1 of 8 · 33.1% of the exam

Applications and integration

Weight: 33.1 percent of the exam. Tests whether you can wire the Claude API into a real product correctly: request shape, streaming, multimodal input, caching, batching, error handling, rate limits, and the tool use loop.

What the exam expects

This is the largest domain on CCDV-F by a wide margin, roughly one question in three. It is also the most mechanical: most questions have a single defensible answer grounded in how the API actually behaves, not in architectural taste. The exam tests whether you have shipped against this API or only read about it.

Expect scenarios written from the perspective of a team already in production: a support bot that forgets context, a caching change that produced no savings, a rate limit incident during a launch, a batch job whose results are attached to the wrong records. You are usually asked one of four things: what is the root cause, what should they do first, what is wrong with this approach, or which change most improves it.

Two habits of mind carry most of the domain. First, the API is stateless and the request body is the entire world the model sees. Second, most silent failures in this domain are not errors at all: they are successful HTTP 200 responses whose stop_reason, usage, or content shape you did not inspect.

The Messages API contract

Every call goes to POST /v1/messages. There is no server side conversation. Continuity exists only because your client stores the transcript and resends it in full on every request.

The request has three prompt-bearing parts, and they render in a fixed order: tools, then system, then messages. That order matters far more than it looks, because it determines what can be cached (see below).

Rules worth memorising:

  • system is a top level parameter, not a role inside messages. (Mid-conversation role: "system" messages inside messages are a separate, model-gated feature for operator instructions that arrive later.)
  • The first message must be user. Consecutive same-role messages are combined into one turn rather than rejected.
  • max_tokens is required, and it is a hard ceiling on everything the model generates, including thinking tokens. A route sized tightly around a short visible answer can start truncating the moment reasoning is enabled on it.
  • Assistant prefill on the final turn returns a 400 on current models. Use structured outputs or a system prompt instruction instead.

The response is a list of content blocks (text, thinking, tool_use, and others), not a string. Flattening it to text is the single most common data modelling bug in this domain, because it silently discards the tool_use blocks the next request needs.

Always branch on stop_reason before touching content:

stop_reasonMeaningWhat your code must do
end_turnFinished naturallyRender normally
max_tokensTruncated at the output ceilingDo not present as complete; raise the budget or shorten the task
tool_useWants a tool executedRun it and continue the loop
refusalDeclined for safety reasonscontent may be empty; surface a refusal path
pause_turnServer tool loop pausedResend to resume

Log the response's request id on every call. It is the identifier Anthropic support traces on, and a client-generated UUID is no substitute.

Delivery: streaming and its limits

Streaming does not make generation faster. It changes when the user sees the first token, and it keeps the HTTP connection active so a long generation does not die on an idle timeout. Both reasons are legitimate; nothing about cost or rate limits changes.

The SDKs guard non-streaming requests with a large max_tokens for exactly this reason. If you hit that guard, the answer is to stream and read the accumulated result with the final message helper, not to suppress the guard or to split the work into artificial chunks.

When handling raw events, message_delta is where stop_reason and final usage arrive. content_block_delta carries incremental content only, and message_start fires before anything has been generated.

Multimodal input: images, PDFs, files, citations

Images go in image content blocks with one of three sources: base64, a URL, or a file_id from the Files API. PDFs go in document blocks with the same three options. The block type must match what the file actually is: an uploaded PNG referenced from a document block is a 400.

Cost and limits are dimension-driven. Claude bills images as visual tokens computed from pixel dimensions, capped by the model's resolution tier, so a 4K screenshot genuinely costs several times a 1366x768 one. Pre-resizing before upload is the direct control when you do not need the fidelity. Requests have both a payload size limit and an image or page count limit, and heavy base64 usually reaches the size limit first.

For PDFs, each page contributes extracted text and an image of the page, which is what lets Claude read charts and layout. A cost forecast built from extracted text alone will undershoot. PDFs must be standard and unencrypted; removing a password is the caller's job.

Choosing a source:

SituationUse
One shot call, small filebase64 inline
Multi-turn conversation with an attachmentFiles API file_id (bytes are not resent every turn)
Same document queried many timesFiles API plus a cache breakpoint after the document

Files persist until you delete them, so lifecycle management is your application's responsibility.

Citations are enabled per document block and make Claude return cited text with a structured location: character offsets for plain text, page numbers for PDFs. Two constraints matter: citations are all-or-none across document blocks, and they are incompatible with an output format schema in the same request.

Cost and throughput: caching, batching, counting, limits

Prompt caching is a prefix match. Any byte change anywhere in the prefix invalidates everything after it. Design for this by ordering content from stable to volatile: frozen system prompt and deterministically serialised tools first, per-session content next, per-request content (timestamps, IDs, the actual question) last, after the final breakpoint.

The diagnostic is usage. Writes on every request with zero reads means something in the prefix changes each time. Both counters at zero with no error usually means the prefix is below the model's minimum cacheable length. Remember also that input_tokens is only the uncached remainder: total input is the sum of the three counters, which is why a heavily cached agent shows a surprisingly small number.

Two second-order effects are worth knowing. A cache entry is only readable once the first response begins streaming, so a parallel fan-out of identical requests all miss. And on current models, cache reads do not count toward your input tokens per minute limit, which makes caching a throughput lever, not just a cost one.

The Batch API processes requests asynchronously at half the standard token price, with its own rate limit pool so bulk work does not starve interactive traffic. It supports the full Messages API feature set, including caching, so a shared prefix across thousands of batch requests compounds both savings. Results come back in arbitrary order: key them by custom_id, never by position. Branch on the result type (succeeded, errored, canceled, expired) before reading a message.

Token counting uses the count_tokens endpoint with the model id you will actually use. Counts are model-specific, and tokenizers built for other providers materially undercount Claude tokens, especially on code and non-English text.

Rate limits are per organisation and per model, measured in requests, input tokens, and output tokens per minute, replenished continuously. Extra API keys add no capacity. Workspace limits can cap a workspace below the organisation total but never above it. max_tokens does not consume output budget; only generated tokens do. Drive alerts from the rate limit response headers rather than from counting 429s after users are already affected.

Failure handling

Distinguish retryable from permanent before writing any loop:

RetryableNot retryable
429 rate limited (honour retry-after)400 invalid request
500 and other 5xx401 authentication
529 overloaded403 permission
Connection errors404 unknown model or endpoint

A bare except around every call turns a typo in a model id into five slow attempts and thirty wasted seconds. Use the SDK's typed exception classes and catch most-specific first.

Also account for what the SDK already does: it retries connection errors, 429, and 5xx with backoff by default. A custom wrapper on top multiplies the attempt count and the worst-case wall clock. Configure max_retries and add only what the SDK does not provide.

Refusals are not errors. They arrive as HTTP 200 with stop_reason: "refusal" and possibly empty content, which is why the stop_reason check has to come before the content read.

Tools and structured outputs

The tool loop has a fixed shape. Claude returns an assistant turn containing one or more tool_use blocks. You append that entire assistant turn to messages, then append a single user message containing a tool_result block for every call, each with the matching tool_use_id. Splitting results across multiple user messages trains the model out of parallel calling. A failed tool still needs a tool_result, marked with is_error: true and an informative message, so Claude can adapt instead of waiting for a result that never comes.

Sequence of the tool use loop between your application and the Claude API: request, tool_use response, local execution, all tool_result blocks returned in one user message, final answer.

Human-in-the-loop approval does not require hand-writing the loop. The SDK tool runner lets you gate inside the tool function or intervene in the per-turn hook before execution, so choose a manual loop only when your control flow genuinely does not fit.

Structured outputs come in two forms: output_config.format with a JSON schema to constrain the response, and strict: true on an individual tool definition (with additionalProperties: false and an explicit required list) to guarantee tool input shape. A schema constrains structure, not truth, and it does not exempt you from max_tokens truncation.

One thing Anthropic does not provide: an embeddings model. Retrieval pipelines use a third-party embedding provider (the documentation points to Voyage AI) and your own vector store, with Claude handling generation over the retrieved context.

How to think through the question

Domain 1 questions are diagnostic more often than they are architectural. Work them in this order.

1. Identify the actual failure signal. Is it an HTTP error, a successful response with unexpected content, or a cost or latency observation? This single split eliminates most distractors. An HTTP 200 with empty content is a refusal, not a network problem. A cost spike with no error is almost always caching or resolution.

2. Name the constraint the scenario states. Interactive latency, a fixed budget, a compliance requirement for traceability, a fleet already near its rate limit. The correct answer serves that constraint. An option that ignores it is wrong even when it is technically sound.

3. Ask what the question is really asking. "What is the root cause" wants the mechanism. "What should they do first" wants the cheapest diagnostic or the highest-leverage fix, not the complete remediation plan. "What is wrong with this approach" wants the flaw, not a redesign.

4. Eliminate compensating controls. Options that add monitoring, retries, validation, or regexes around a broken mechanism are the most common wrong answers in this domain, because they are things real teams actually do. If a cleaner mechanism exists (structured outputs instead of brace-matching regex, is_error instead of skipping a tool result, the Files API instead of trimming history), that is the answer.

5. Eliminate invented API surface. Distractors frequently name a parameter, header, or endpoint that does not exist: a conversation_id, an embeddings endpoint, a password field on a document block, a request-level strict flag. If you cannot picture the field in a real request body, it is not real.

Worked example. A due diligence workflow asks 30 questions about the same 200 page PDF, one per request, within a few minutes. Costs are far higher than expected and every request has similar latency regardless of how simple the question is.

Step 1: the signal is cost plus flat latency, with no errors. So this is about what is being reprocessed, not about correctness. Step 2: the stated constraints are a repeated large prefix and a short time window, which is exactly the shape caching is for. Step 3: the question asks which combination most reduces cost and latency, so we want the mechanism, not a workaround. Step 4: eliminate "send the 30 requests in parallel" (a compensating control that actually defeats caching, since the entry is not readable until the first response starts streaming) and "split the PDF into 30 keyword-selected chunks" (reintroducing a retrieval failure mode where the whole document already fits). Step 5: "concatenate all 30 questions into one request" uses only real API surface and does reduce processing to one pass, but it couples 30 independent answers into one generation and risks the output ceiling. The answer is the Files API for file_id plus a cache breakpoint after the document: the prefix is written once and read cheaply 29 times, which addresses both the cost and the flat latency.

Exam traps

  • Treating the API as stateful. Any option involving a session id, a stored transcript, or sending only the delta is wrong. Tempting because most chat APIs developers have used do maintain sessions.
  • Reading content[0] before checking stop_reason. Tempting because it works in the happy path and in every quickstart snippet.
  • Assuming input_tokens is the whole prompt. It is the uncached remainder. Tempting because the field name says otherwise.
  • Adding API keys to raise rate limits. Limits are per organisation. Tempting because per-key quotas are common elsewhere.
  • Lowering max_tokens to relieve an input token limit. Input and output are metered separately. Tempting because it feels like reducing overall load.
  • Fixing stale RAG answers with a stronger prompt. If the index was not rebuilt, the new text never reached the model. Tempting because prompting is the cheapest thing to change.
  • Joining batch results by position. Results are unordered; use custom_id. Tempting because the corruption is silent and only shows up in a fraction of rows.
  • Wrapping every call in a bare retry loop. It converts fast, deterministic errors into slow ones and duplicates SDK behaviour. Tempting because "retry on failure" reads as defensive engineering.
  • Regex-extracting JSON instead of using structured outputs. Tempting because the regex mostly works and the retry hides the rest.
  • Assuming a manual tool loop is required for approval gates. The tool runner supports gating. Tempting because "I need control" sounds like it implies owning the loop.

Quick reference

SymptomFirst thing to check
Model forgets earlier turnsIs the full history in messages?
Answers cut off mid sentencestop_reason is max_tokens; thinking shares the budget
Empty content, HTTP 200stop_reason is refusal
Caching saves nothingcache_read_input_tokens is 0; diff the prefix byte for byte
Both cache counters 0, no errorPrefix below the model's minimum cacheable length
Payload grows every turnBase64 attachment being resent; move to the Files API
Image bill 3x a peer'sResolution; downsample before upload
Wrong answers attached to wrong rows in a batchPositional join instead of custom_id
Model stopped calling tools in parallelTool results split across multiple user messages
429s during a launch rampAcceleration limits; ramp gradually and honour retry-after

Ready to test this domain?

Drill mode gives instant feedback: pick a wrong answer and you immediately see why it is wrong.

Start the drill

Not an official source. This is a free, independent study resource from siasola, built by an engineer who sat these exams and wanted better prep material to exist. It is not affiliated with, endorsed by, or sponsored by Anthropic. Claude is a trademark of Anthropic, PBC. Exam facts follow the official exam guides; registration for the real exams happens through the Anthropic Partner Academy and Pearson VUE, not here.