Messages API Roles and Content Block Types Reference
A dense, scannable reference for the two message roles and the four content block types you'll encounter building against the Messages API.
Keep this page open while wiring up requests - it's meant to be looked up, not read start to end.
How to Use This Reference
- Look up a role or block type by name in the tables below.
- Each row shows which turn(s) it can appear in and the minimal shape of its JSON.
- The "Appears In" column tells you whether a block is something you send, something Claude sends back, or both.
- Cross-check against Understanding Roles and Turns in the Messages API if a row doesn't make sense in isolation.
Roles
| Role | Who sends it | Notes |
|---|---|---|
user | Your application | Represents input to Claude - questions, tool results, images. Must be the first entry in messages and must alternate with assistant. |
assistant | Claude (echoed back by you on the next turn) | Represents Claude's own prior replies, including any tool_use blocks. You append it after each response to preserve history. |
system (not a role in messages) | Your application | A separate top-level request parameter, not a messages entry - sets persona/constraints for the whole conversation. |
Content Block Types
| Type | Appears In | Minimal Shape |
|---|---|---|
text | user, assistant | {"type": "text", "text": "..."} |
image | user only | {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": "..."}} |
tool_use | assistant only | {"type": "tool_use", "id": "toolu_...", "name": "get_weather", "input": {"location": "Paris"}} |
tool_result | user only | {"type": "tool_result", "tool_use_id": "toolu_...", "content": "..."} |
Text Blocks
{"role": "user", "content": [{"type": "text", "text": "What is the capital of France?"}]}| Field | Type | Notes |
|---|---|---|
type | "text" | Always the literal string "text". |
text | string | The message content. A plain string content value (no list) is shorthand for a single text block. |
Image Blocks
{
"role": "user",
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": base64_data}},
{"type": "text", "text": "What's in this image?"},
],
}| Field | Type | Notes |
|---|---|---|
type | "image" | Always "image". |
source.type | "base64" or "url" | base64 embeds the image data directly; url references a publicly reachable image. |
source.media_type | string | Required for base64 sources, e.g. "image/png", "image/jpeg". |
source.data | string | Base64-encoded image bytes, required for base64 sources. |
Only appears in user turns - Claude produces text describing images, never image blocks of its own.
Tool Use Blocks
# Appears inside an assistant turn's content, produced by Claude - you don't write this by hand.
{
"type": "tool_use",
"id": "toolu_01A09q90qw90lq917835lq9",
"name": "get_weather",
"input": {"location": "Paris, France"},
}| Field | Type | Notes |
|---|---|---|
type | "tool_use" | Always "tool_use". |
id | string | Unique ID for this tool call - echo it back in the matching tool_result. |
name | string | The tool name, matching one of the tools you declared on the request. |
input | object | Parsed arguments matching the tool's input_schema. Always parse with your JSON tooling rather than string-matching - never assume a fixed serialization. |
Tool Result Blocks
{
"role": "user",
"content": [
{"type": "tool_result", "tool_use_id": "toolu_01A09q90qw90lq917835lq9", "content": "72F and sunny"},
],
}| Field | Type | Notes |
|---|---|---|
type | "tool_result" | Always "tool_result". |
tool_use_id | string | Must match the id of the tool_use block it's answering. |
content | string or list of blocks | The tool's output. Can itself be a list of text/image blocks for richer results. |
is_error | boolean (optional) | Set true if the tool call failed, so Claude knows to adapt rather than treat the content as a valid result. |
Combining Block Types in One Turn
| Scenario | Turn Content |
|---|---|
| Plain question | [{"type": "text", "text": "..."}] (or a bare string) |
| Question about an image | [{"type": "image", ...}, {"type": "text", "text": "..."}] |
| Claude requesting a tool call | [{"type": "text", "text": "..."}, {"type": "tool_use", ...}] |
| Returning a tool result plus a follow-up comment | [{"type": "tool_result", ...}, {"type": "text", "text": "..."}] |
Multiple blocks of the same or different types can coexist in a single turn's content list - role alternation applies to the turn as a whole, not to individual blocks.
FAQs
Can a plain string be used instead of a list of content blocks?
Yes - content: "some text" is shorthand for content: [{"type": "text", "text": "some text"}]. Use the list form once you need more than one block or a non-text block type.
Which block types can Claude produce, versus only send?
Claude produces text and tool_use blocks in assistant turns. image and tool_result blocks are things your application sends in user turns; Claude never generates them.
What identifies which tool_result answers which tool_use?
The tool_use_id field on the tool_result block must exactly match the id field Claude generated on the corresponding tool_use block.
Can one turn contain multiple tool_use blocks?
Yes - Claude can request several tool calls in a single assistant turn. When that happens, return all the matching tool_result blocks together in a single user turn, not split across multiple turns.
What does is_error do on a tool_result block?
It tells Claude the tool call failed rather than succeeded, so Claude reasons about the failure and can try a different approach instead of treating the error message as valid data.
Is system a content block type?
No. system is a separate top-level request parameter, not a role or a content block inside messages. It has no block types of its own.
Do image blocks work in assistant turns?
No - image blocks only appear in user turns, since they represent input you're providing to Claude, not something Claude generates.
What's the difference between source.type "base64" and "url" for images?
base64 embeds the raw image bytes directly in the request; url instead points to a publicly reachable image URL that Claude fetches. Use base64 for local files and url when the image is already hosted.
Should I parse tool_use input as JSON or treat it as a raw string?
Always parse it - input is delivered as a structured object matching your tool's schema, and relying on exact string formatting (like specific escaping) is fragile and can break across model versions.
Can tool_result content be more than plain text?
Yes - content on a tool_result block can be a string, or a list of blocks (such as text and image) for richer results, like returning a generated chart image alongside a text summary.
Does the order of blocks within a single turn's content list matter?
Generally yes for readability and how Claude processes multi-block context - place explanatory text before or after the block it refers to consistently, though there's no strict alternation rule within one turn's content list the way there is across turns.
Related
- Understanding Roles and Turns in the Messages API - the conceptual model behind roles and turns.
- Handling Mixed Content Blocks: Text, Image, and Tool Results in One Turn - worked examples combining multiple block types.
- Messages API Basics - runnable examples using several of these block types.
Stack versions: Written against the Claude model lineup current as of ~June 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (the default), and Claude Haiku 4.5 - and the official
anthropicPython SDK (latest 0.x release). Model names, SDK versions, and pricing move quickly - verify current specifics at platform.claude.com/docs before relying on them.