Anatomy of a Model API Call
Messages, roles, system prompts, content blocks, stop reasons, and usage — every field of a real request and response, and what each one is for.
Most AI feature bugs aren't model bugs. They're integration bugs: code that reads content[0].text and crashes when the first block is a thinking block, a handler that treats a truncated response as complete, a chat feature that puts instructions in the wrong field, or a cost dashboard that never logged usage. Each of these comes from not knowing what one field of the request or response was for.
This lesson walks through a real Messages API call to Claude, field by field: what you send, what comes back, and what your code should do with each part. By the end you'll have a small, typed wrapper you can reuse for every feature in this course, one that handles content blocks, stop reasons, refusals, and usage correctly from day one.
A complete request and response
Here's a Deskmate request at the HTTP level, so nothing is hidden by an SDK. It asks for a one-sentence summary of a ticket:
curl https://api.anthropic.com/v1/messages \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2026-10-21" \
-H "content-type: application/json" \
-d '{
"model": "claude-sonnet-5-5",
"max_tokens": 2000,
"system": "You summarize support tickets for Deskmate agents in one sentence.",
"messages": [
{
"role": "user",
"content": "<ticket>CSV export stuck at 0% since this morning, Acme Ops workspace, last 90 days of tickets.</ticket>"
}
],
"output_config": { "effort": "low" }
}'And here's the shape of what comes back (IDs shortened, and usage trimmed to the fields discussed below):
{
"id": "msg_01...",
"type": "message",
"role": "assistant",
"model": "claude-sonnet-5-5",
"content": [
{ "type": "thinking", "thinking": "", "signature": "EqQB..." },
{ "type": "text", "text": "Customer's 90-day ticket CSV export in the Acme Ops workspace has been stuck at 0% since this morning." }
],
"stop_reason": "end_turn",
"stop_sequence": null,
"stop_details": null,
"usage": {
"input_tokens": 61,
"output_tokens": 48,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0,
"output_tokens_details": { "thinking_tokens": 21 }
}
}The numbers are illustrative, but the structure is exactly what your code has to handle. Notice that the answer isn't a string. It's a list of content blocks, and the first one here isn't even text. Let's go through it.