A message in the Claude Messages API has a role (user or assistant) and content. For plain chat, content can be a simple string — but that is shorthand. The real structure is an array of content blocks, each a JSON object with a type field. A single user turn can carry a text block, two image blocks, and a PDF document block; a single assistant turn can carry text plus several tool-use requests. This block model is what lets one API surface handle chat, vision, documents, and agents without separate endpoints.
The main block types and where they live
| Block type | Appears in | What it carries |
|---|---|---|
text | User and assistant turns | Plain text; assistant text blocks may include citations |
image | User turns | An image via base64, url, or Files API file source |
document | User turns | A PDF or plain-text document; per-document citations toggle |
tool_use | Assistant turns | A tool invocation: id, name, input |
tool_result | User turns | Your tool's output, keyed by tool_use_id |
thinking | Assistant turns | Reasoning content plus a cryptographic signature |
The placement rules follow the conversation's logic. Blocks that provide input to the model — text, images, documents, tool results — belong in user turns. Blocks the model produces — text, tool-use requests, thinking — appear in assistant turns, and when you continue a conversation you append the assistant's content array back into history exactly as you received it. Thinking blocks in particular must be passed back unchanged; modifying, reordering, or filtering them in the latest assistant turn is rejected with a 400 error.
Mixing blocks in a single turn
Order within a turn matters more than most teams expect. Anthropic's vision guidance says Claude works best with images placed before the text that asks about them, and the same "data first, question last" pattern applies to documents. A well-shaped multimodal turn looks like: image blocks, document blocks, then one text block with the actual instruction.
message = {"role": "user", "content": [
{"type": "image",
"source": {"type": "base64", "media_type": "image/png",
"data": img_b64}},
{"type": "document",
"source": {"type": "base64", "media_type": "application/pdf",
"data": pdf_b64},
"citations": {"enabled": True}},
{"type": "text", "text": "Does the chart match the report's claims?"},
]}
Source types vary by platform: the Claude API and Claude Platform on AWS accept base64, url, and Files API file references for images and PDFs, while Amazon Bedrock and Google Vertex AI currently accept base64 only. See Multimodal Turns for size and count limits.
Nested content inside tool results
A tool_result block's content field accepts either a plain string or its own list of content blocks. That nesting is what allows a tool to return rich output rather than flattened text — for example, Anthropic's tool-search documentation shows custom search tools returning tool_reference blocks inside a standard tool_result, which the API then expands into full tool definitions. When a tool fails, the same block carries "is_error": true so the model knows to adjust (covered in Tool Result Errors). For exactly which nested types each platform accepts, check the official tool-use documentation for your platform.
Blocks, caching, and streaming
Two other features hang off the block structure. Prompt caching places cache_control markers on individual blocks — tool definitions, system blocks, and text, image, document, tool-use, and tool-result blocks in message content are all cacheable, which is why stable block ordering matters for cache hits. And when streaming, each block arrives as its own content_block_start / content_block_delta / content_block_stop sequence with an index matching its final position in the array — the array structure is preserved event by event.
Where to go next
For the vision and document specifics, continue with Multimodal Turns. For how blocks stream over the wire, see Streaming With Tool Use, and for the caching angle, Cache Read vs Write Tokens.