Streaming Event Types Reference
A dense lookup for every event type the Messages API emits while streaming, its fields, and when it fires in the event lifecycle.
Search across all documentation pages
A dense lookup for every event type the Messages API emits while streaming, its fields, and when it fires in the event lifecycle.
content_block_delta handler and need to know what event.delta.type can be.| Order | Event type | Fires | Purpose |
|---|---|---|---|
| 1 | message_start | Once, first | Opens the message; carries id, model, role, and initial (near-zero) usage. |
| 2 | content_block_start | Once per content block | Opens a block; carries the block's type (text, tool_use, or thinking) and index. |
| 3 | content_block_delta | Many times per block | Carries an incremental piece of that block's content - see Delta Types below. |
| 4 | content_block_stop | Once per content block | Closes a block; the block's content is now complete for that index. |
| - | (steps 2-4 repeat) | Per additional block | A response can contain multiple blocks (e.g. thinking then text then tool_use) in sequence. |
| 5 | message_delta | Once, near the end | Carries stop_reason, stop_sequence, and finalized usage (output tokens). |
| 6 | message_stop | Once, last | Signals the stream is complete; no further events follow. |
| - | ping | Any time (rare) | A keep-alive event with no payload; safe to ignore. |
| - | error | Any time | Signals a mid-stream error (e.g. an overloaded model); ends the stream. |
content_block_delta)delta.type | Belongs to block type | Key field | Meaning |
|---|---|---|---|
text_delta | text | delta.text | The next fragment of generated prose. |
input_json_delta | tool_use | delta.partial_json | The next fragment of a tool call's JSON arguments string. |
thinking_delta | thinking | delta.thinking | The next fragment of extended-thinking reasoning text. |
signature_delta | thinking | delta.signature | A cryptographic signature fragment for the thinking block, sent near its close. |
message_start| Field | Type | Description |
|---|---|---|
message.id | str | Unique identifier for this message. |
message.model | str | The model that generated the response (e.g. claude-sonnet-5). |
message.role | str | Always "assistant" for API responses. |
message.usage.input_tokens | int | Input token count, known immediately. |
message.usage.output_tokens | int | Near-zero at this point; finalized later in message_delta. |
content_block_start / content_block_stop| Field | Type | Description |
|---|---|---|
index | int | Which content block this event belongs to; the key for tracking per-block state. |
content_block.type | str | "text", "tool_use", or "thinking". |
content_block.name | str | Tool name - present only when type is "tool_use". |
content_block.id | str | The tool_use_id - present only when type is "tool_use". |
message_delta / message_stop| Field | Type | Description |
|---|---|---|
delta.stop_reason | str | Why generation stopped: "end_turn", "max_tokens", "tool_use", "stop_sequence". |
delta.stop_sequence | str | None | The custom stop sequence matched, if stop_reason is "stop_sequence". |
usage.output_tokens | int | Finalized output token count for the whole message. |
| (none) | - | message_stop carries no payload beyond type - it's a pure signal. |
| You want | Use |
|---|---|
| Only the text, as it arrives | for text in stream.text_stream: |
| Every raw event, all types | for event in stream: |
The complete Message after streaming | stream.get_final_message() after iteration finishes |
| Async equivalents | async for text in stream.text_stream: / async for event in stream: on AsyncAnthropic |
message_start, always. It arrives before any content block exists.
message_stop, always - it's a pure signal event with no payload of its own.
Input tokens are in message_start.message.usage.input_tokens. Output tokens finalize in message_delta.usage.output_tokens.
Check content_block.type on the content_block_start event for that block's index - it's "text", "tool_use", or "thinking".
event.delta.partial_json on content_block_delta events where event.delta.type == "input_json_delta" - accumulate these before parsing as JSON.
No, it's a keep-alive with no payload. Safe to ignore in a type-based dispatch (it just won't match any of your handled cases).
Why the model stopped generating: "end_turn" (natural completion), "max_tokens" (hit the token cap), "tool_use" (paused to call a tool), or "stop_sequence" (matched a custom stop string).
Yes - for example a thinking block followed by a text block, or a text block followed by one or more tool_use blocks, each opened and closed independently by index.
It streams a cryptographic signature associated with an extended-thinking block, used to verify the thinking content wasn't tampered with when passed back in a later turn.
It means the stream ended abnormally mid-generation. Treat it the same as a dropped connection: whatever content arrived before it is incomplete, and the request should typically be retried.
content_block_delta carries incremental content inside one block (text, JSON, or thinking fragments). message_delta carries message-level metadata (stop_reason, final usage) that's only known once generation is wrapping up.
message_start.message.model - it echoes back the model you requested (useful if your code allows a model alias to resolve to a specific dated snapshot).
input_json_delta in practice.thinking_delta and signature_delta.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.
Reviewed by Chris St. John·Last updated Jul 19, 2026