Applications and Integration (33.1%)
What the exam tests: turning requirements into working Claude integrations: API mechanics, software engineering basics, application design across Claude's interfaces, and configuration management. This is a third of your score; study it hardest.
Understanding requirements (3.4%)
Scenario items start with a business need and hide the deciding constraint in one phrase. Read for it before reading the options.
Phrase in the scenario Usually points to
"overnight," "not urgent," "cost is the primary concern" Message Batches API "real time," "chat UI," "users see text as it arrives" Streaming "same long document, many questions" Prompt caching
"must return valid JSON every time" Structured outputs or strict tool use "reusable across several apps" MCP server
"data must stay in our AWS account" Claude on Amazon Bedrock or Claude Platform on AWS "untrusted user content" Input isolation plus guardrails
Separate functional requirements (what the system does) from infrastructure requirements (latency, throughput, region, data residency, compliance, budget). Many wrong options satisfy the first and violate the second.
Systems life cycle (2.8%)
Claude apps follow the same life cycle as any system: plan, design, build, test, deploy, operate, maintain, retire. What is different is that the model is a dependency that changes underneath you. Plan for it:
Pin model versions in production and upgrade deliberately, behind an evaluation run. Version prompts like code, with review and rollback.
Monitor in production (latency, error rates, token usage, output quality samples). Plan deprecations. Anthropic retires older models on a published schedule; track it.
Claude API mechanics (6.8%)
Everything goes through one endpoint: POST /v1/messages. Tools, vision, thinking, and structured outputs are features of that endpoint, not separate APIs. Request anatomy. Required fields are model, max_tokens, and messages. Common optional fields are system, tools, tool_choice, thinking, output_config (for effort and structured output format), stop_sequences, metadata, and stream. Auth uses the x-api-key header plus anthropic-version; beta features add an anthropic-beta header.
- import anthropic
- client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY
- response = client.messages.create(
- model="claude-opus-5-5",
- max_tokens=1024,
- system="You are a concise support assistant.",
messages=[{"role": "user", "content": "How do I reset my password?"}], )
print(response.content[0].text, response.stop_reason, response.usage)
Messages are stateless. The API stores no conversation. You resend the full history on every call, with user and assistant turns alternating. Content can be a string or a list of typed blocks: text, image, document, tool_use, tool_result, thinking.
Response anatomy. content is a list of blocks. stop_reason tells you why generation ended. Always check it before reading content. stop_reason Meaning What to do
end_turn Model finished naturally Use the answer
max_tokens Hit your max_tokens cap Output is truncated; raise the cap or continue stop_sequence Hit one of your stop sequences Expected if you set them tool_use Model wants to call a tool Run the tool, return tool_result pause_turn A long server-tool turn was paused Send the response back to let it continue refusal Safety classifiers declined Handle gracefully; read stop_details, consider a fallback Usage. usage reports input_tokens, output_tokens, cache_creation_input_tokens, and cache_read_input_tokens. Log these on every call; they are your cost data.
Streaming. Set stream: true (or use the SDK's .stream() helper) to receive server-sent events: message_start, then for each block content_block_start, content_block_delta (with text_delta, input_json_delta for tool input, or thinking_delta), content_block_stop, then message_delta (carrying stop_reason and final usage) and message_stop. Streaming improves perceived latency and is required in practice for very large max_tokens, because long nonstreaming requests can hit HTTP timeouts. Vision and documents. Send images as image blocks and PDFs as document blocks, either base64-encoded or by reference to an upload in the Files API (upload once, reuse by file_id). Put the image or document before the text question. Turn on citations on document blocks to get answers tied to exact passages.
Thinking. Current models use adaptive thinking (thinking: {type: "adaptive"}): Claude decides how much to reason. You control depth and spend with effort (output_config: {effort: "low" | "medium" | "high" | "xhigh" | "max"}). The older fixed budget_tokens setting is deprecated on recent models and rejected on the newest. Thinking tokens are billed as output. Batch API. POST /v1/messages/batches accepts many requests, each with a custom_id. Results arrive asynchronously at a 50% discount. Most batches finish within an hour; any request not processed within 24 hours expires unbilled. A batch holds up to 100,000 requests or 256 MB, and results stay downloadable for 29 days (batch docs). Results can come back in any order, so match them by custom_id, never by position.
Choose When
Realtime Messages API A user or system is waiting; interactive chat; agent loops Message Batches API Large, latency-tolerant jobs: evaluations, backfills, nightly classification, report generation Third-party platforms. Claude is available through Amazon Bedrock, Google Cloud Vertex AI, and Microsoft Foundry, plus Anthropic-operated Claude Platform on AWS. Each uses its own client class (for example AnthropicBedrock... or AnthropicVertex in Python), its own auth (AWS IAM, Google ADC, Azure credentials), and sometimes different model ID formats. Feature availability can lag the first-party API, so check before you design around a beta feature. Data access patterns. The Messages API sees only what you put in the request. To give Claude your data, you either insert it into context (retrieval, RAG), let Claude fetch it through tools or MCP, or reference uploaded files. Choose based on freshness, size, and access control: tools and MCP give live, permission-checked access; pasted context goes stale and costs tokens on every call.
Software engineering foundations (7.4%)
This is the second-heaviest skill and is mostly general engineering applied to Claude. REST and JSON. Know HTTP verbs, status codes, headers, and JSON schema basics. The SDKs wrap a REST API; you can always drop to raw HTTP.
Asynchronous programming. Use the async clients (AsyncAnthropic) to run many calls concurrently. Bound concurrency to stay under rate limits.
Error handling and retries. The SDKs retry 408, 409, 429, and 5xx errors twice by default with exponential backoff. Honor retry-after on 429s. Never retry 400s unchanged. Version control and SDLC. Prompts, tool schemas, CLAUDE.md files, and eval sets belong in git with review.
Code review and refactoring. Expect scenarios about using Claude Code for small refactors (rename, extract function) and large ones (framework migration, codebase modernization): plan first, work in small verified steps, and keep tests green.
HTTP status Error type Retry?
- 400 invalid_request_error No, fix the request
- 401 authentication_error No, fix the key
- 403 permission_error No
- 404 not_found_error (often a bad model ID) No
- 413 request_too_large No, shrink the request
- 429 rate_limit_error Yes, with backoff and retry-after
- 500 api_error Yes
- 529 overloaded_error Yes, with backoff
Claude application design (8.6%)
This is the heaviest single skill on the exam.
Interfaces interpret instructions differently. The same request behaves differently depending on where it runs:
Interface Where instructions come from
claude.ai and Claude Desktop Anthropic's product system prompt, plus Projects instructions, plus your message Claude Code CLAUDE.md files, settings, Skills, slash commands, plus your message Claude API Only what you send: your system prompt, tools, and messages Agent SDK The Claude Code harness defaults plus your options and prompt On the API there is no hidden product prompt, so a prompt that works in claude.ai may need more context when moved to the API.
Content boundaries. Keep trusted instructions (system prompt) separate from untrusted data (user uploads, web pages, tool output). Wrap untrusted data in clearly labelled XML tags and tell Claude to treat it as data.
Schema design. Design tool and output schemas that are flat, explicit, and well-described. Use enums for closed sets, mark required fields, and avoid ambiguous free-text fields when a structured one will do. Session hygiene. Long sessions accumulate stale context. Start fresh sessions for new tasks, clear or compact history, and do not let one user's data bleed into another's session. Plugin management. In Claude Code, plugins bundle commands, agents, Skills, hooks, and MCP servers for distribution. Install only trusted plugins, pin their versions, and review what each one adds.
Configuration management (4.1%)
CLAUDE.md files hold project memory and instructions for Claude Code (see Chapter 4). settings.json holds permissions, hooks, environment variables, and model defaults at user, project, and local levels.
Model version pinning. Use exact model IDs in production. An alias that silently moves to a newer model can change behavior overnight.
Prompt versioning. Store prompts with version numbers, link each to eval results, and roll back on regression.
Plugin dependencies. Track which plugins and MCP servers a project needs and at what versions.
Worked example 3.1: streaming to a chat UI
A support chat should show text as it is generated. With the Python SDK's streaming helper: import anthropic
- client = anthropic.Anthropic()
- with client.messages.stream(
- model="claude-sonnet-5-5",
- max_tokens=2048,
- system="You are a friendly support agent for Acme Cloud.",
messages=[{"role": "user", "content": "My deploy keeps timing out. What should I check?"}],
- ) as stream:
- for text in stream.text_stream:
- send_to_browser(text) # forward each chunk as it arrives
final = stream.get_final_message() # full message, stop_reason, usage log_usage(final.usage)
if final.stop_reason == "max_tokens":
send_to_browser("\n[Response was cut short. Ask me to continue.]")
Under the hood the API sends server-sent events in this order: message_start, then for each content block content_block_start, many content_block_delta events, content_block_stop, then message_delta (with stop_reason and output usage) and message_stop. Occasionally a ping or an error event appears; an error mid-stream (such as overloaded_error) means you should retry the request.
If your backend relays the stream to a browser, the backend-to-browser hop can use server-sent events or a websocket. The Claude API hop is always server-sent events over HTTP.
Worked example 3.2: concurrency without breaking rate limits
A nightly enrichment job must call Claude 2,000 times but a user is not waiting. Two options are correct depending on deadline: the Batch API (cheapest), or bounded async concurrency (fastest). The async version: import asyncio
import anthropic
client = anthropic.AsyncAnthropic(max_retries=4) # SDK retries 429/5xx with backoff limit = asyncio.Semaphore(20) # at most 20 requests in flight
- async def enrich(record):
- async with limit:
- msg = await client.messages.create(
- model="claude-haiku-5-5",
- max_tokens=300,
messages=[{"role": "user", "content": f"Categorize this product: {record['title']}"}],
- )
- return record["id"], msg.content[0].text
- async def main(records):
- return await asyncio.gather(*(enrich(r) for r in records))
The semaphore is the key line. Unbounded gather over 2,000 calls fires them all at once and turns into a wall of 429 errors.
Worked example 3.3: a Message Batches job end to end
"messages": [{"role": "user", "content": f"Sentiment (positive/negative/neutral): {r['text']}"}],
- },
- }
- for r in reviews
- ])
while client.messages.batches.retrieve(batch.id).processing_status != "ended": time.sleep(60)
- labels = {}
- for item in client.messages.batches.results(batch.id):
- if item.result.type == "succeeded":
labels[item.custom_id] = item.result.message.content[0].text.strip()
- else: # errored, canceled, or expired
- retry_queue.append(item.custom_id)
- Points the exam likes:
Results are keyed by custom_id and can arrive in any order.
Each result has a type: succeeded, errored, canceled, or expired. Expired requests are not billed; resubmit them.
Batch requests can use most Messages features, including tools, system prompts, and prompt caching (shared prefixes across batch items can hit cache).
Batches are for throughput and cost, not latency.
Worked example 3.4: documents, the Files API, and citations
A policy assistant answers questions about a 120-page employee handbook. The handbook rarely changes, users ask many questions, and answers must quote the source. handbook = client.files.upload(file=open("handbook.pdf", "rb"))
- response = client.messages.create(
- model="claude-sonnet-5-5",
- max_tokens=1024,
system="Answer only from the handbook. If it does not cover the question, say so.", messages=[{
{"type": "text", "text": "How many days of parental leave do I get?"}, ],
Files API. Upload once; reference by file_id instead of resending base64.
Prompt caching. The cache_control marker on the document makes repeat questions cheap.
Citations. Each answer comes with the exact cited passage and page range, which supports the "skepticism toward confident output" principle in Chapter 7.
Note the order: document first, question last. Citations cannot be combined with structured outputs in the same request.
Worked example 3.5: vision input
An insurance app extracts damage descriptions from claim photos.
- import base64
- with open("bumper.jpg", "rb") as f:
- img = base64.standard_b64encode(f.read()).decode()
- response = client.messages.create(
- model="claude-sonnet-5-5",
- max_tokens=500,
- messages=[{"role": "user", "content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": img}},
{"type": "text", "text": "Describe visible vehicle damage. List each damaged part."}, ]}],
)
Design notes: images cost input tokens in proportion to their size, so resize large photos before sending; put the image before the question; and validate the output (a photo of a different car will still get a confident description).
Worked example 3.6: same code, different platform
A bank moves the handbook assistant to Amazon Bedrock to keep inference inside its AWS account. What changes?
Concern First-party API Amazon Bedrock
Client anthropic.Anthropic() Bedrock client class from the Anthropic SDK (or AWS SDK) Auth x-api-key API key AWS IAM credentials and roles
Model ID claude-sonnet-5-5 Bedrock-format ID with an anthropic. prefix Billing Anthropic AWS account, Bedrock pricing
Feature timing New features first Some features arrive later or differ The Messages request body is largely the same. The design work is checking that every feature you rely on (Files API, a specific server tool, a beta) is available on the target platform.
Worked example 3.7: configuration management in practice
A team ships a support assistant and wants safe change control. A practical layout:
golden_set.jsonl # 200 real, anonymized tickets with expected outcomes run_eval.py
config/
production.yaml # model: claude-sonnet-5-5, prompt: system.v14.md, effort: medium CLAUDE.md # how to run tests and evals, for Claude Code users
.claude/settings.json # shared permissions and hooks
The release rule: a new prompt or model version ships only after run_eval.py shows it matches or beats the current version on the golden set, and the change is reviewed like code. Rollback is a one-line config change.
Worked example 3.8: reading the requirement
Scenario. "Our legal team needs a tool that reviews incoming NDAs against our standard positions. Reviews must be done within an hour of receipt, documents must not leave our Google Cloud tenancy, and we process about 40 per day."
Break it down:
Functional: compare an NDA to standard positions; flag deviations.
Infrastructure: Google Cloud tenancy (points to Claude on Vertex AI or Claude Models on Google Cloud), one-hour turnaround (synchronous calls are fine; Batch also meets it at 40 per day), low volume (cost is not the main driver).
Implied: the standard positions are a stable, reusable prefix (cache them), and output should be structured (clause, deviation, risk, suggested language).
The best answer in an exam item would mention the platform constraint first, because it eliminates options immediately.
Scenario drills
A dashboard shows Claude-generated summaries of yesterday's sales. A product owner asks for streaming. Is it worth it?
A developer's tool-use requests fail with a 400 saying a tool_result has no matching tool_use. What did they do wrong?
Two users of the same app see each other's earlier questions referenced in answers. What design flaw is likely?
A team's Batch job returns 3% expired results. Were they billed, and what should they do?
A team using a beta feature on the first-party API plans to move to Vertex AI next week. What should they check first?
A request returns stop_reason: "refusal". What should the app do?
Why should prompts live in version control rather than in a database field edited through an admin page with no history?
A data pipeline sends the same 50-page reference PDF in 10,000 batch requests. Name two ways to cut cost.
Answers:
No. Nobody watches the generation live, so streaming adds complexity without a user benefit; a Batch job overnight is a better fit. They appended only the text of the assistant turn, dropping the tool_use blocks; append the full response.content.
Shared conversation state or cache keyed without the user or tenant, a session-hygiene failure; isolate history per user. Expired requests are not billed. Resubmit them in a new batch.
Whether that feature is available on Vertex AI, and the Vertex client, auth, and model ID format.
Show a graceful message, log the stop_details category, and if appropriate retry on a fallback model. Review, diffing, rollback, and linking each version to eval results.
Upload it once through the Files API and add a cache breakpoint after it so the shared prefix is cached; and use the cheapest model that passes evals.
Common traps
Treating the Messages API as stateful. You must resend history.
Reading content without checking stop_reason, and missing a truncated or refused response.
Retrying 400 errors, or not retrying 429 and 529.
Matching batch results by order instead of custom_id.
Using the batch API for anything a user is waiting on.
Assuming a beta feature is on Bedrock or Vertex the day it ships.
Using a floating model alias in production.
A chatbot shows a blank screen for 20 seconds, then the full answer. What change fixes perceived latency?
Your code reads response.content[0].text and sometimes gets half a sentence. What did it fail to check?
You submit 5,000 batch requests and write results to a list in order. What is the bug? Which HTTP errors should your client retry?
A prompt that worked in claude.ai gives worse results via the API. Name one likely reason.
Answers: Stream the response. stop_reason, which was max_tokens. Batch results arrive in any order; key them by custom_id. 429, 500, 529 (and 408, 409, connection errors). The API has no product system prompt, so context claude.ai supplied is missing.