Setting stream: true turns a single JSON response into a sequence of server-sent events. The full lifecycle is: one message_start event (carrying an initial, mostly-empty message object with a starting usage), then one content_block_start / a run of content_block_delta / content_block_stop cycle per content block, then a top-level message_delta event (carrying the final stop_reason, any stop_sequence, and cumulative output usage), and finally message_stop. Periodic ping events may appear anywhere in the stream as keep-alives and should simply be ignored. The point of streaming is perceived latency — the user sees the first tokens almost immediately instead of waiting for the whole response — not a change in what the model computes or how much it costs.
Delta types differ by block
A content_block_delta event's shape depends on the type of block it belongs to: a text block streams text_delta events, each with a small chunk of the growing string; a tool_use block streams input_json_delta events, each carrying a partial_json fragment; a thinking block streams thinking_delta events and, at the very end, a single signature_delta event that carries a cryptographic signature over the completed thinking content. Each content_block_start event tells you the index and type of the block that's about to stream, which matters the moment a response has more than one block in flight conceptually (they still arrive in order, but tracking index keeps multi-block accumulation unambiguous).
Tool use over a stream
When Claude streams a tool call, the arguments arrive as a series of input_json_delta events containing partial JSON fragments, not one clean object. Your code must concatenate these fragments into a per-block string buffer and parse the accumulated string only once content_block_stop fires for that block — parsing a partial fragment as JSON on every delta will throw on most of them, since a fragment like {"query": "par is not valid JSON on its own. Most official SDKs expose a higher-level stream helper that accumulates this for you and emits a fully-formed message at the end; using the raw event stream directly is what the exam expects you to be able to reason about even if your actual code uses the helper.
Common exam distractor
An option that says a stream can be inspected for a final, reliable stop_reason on every delta is a trap. Early in the stream stop_reason is null in the message_start payload; it only becomes final and trustworthy on the message_delta event near the end of the stream. Reading it from an earlier event and acting on it is reading an incomplete value.
Errors mid-stream
A stream can also emit an error event after generation has already begun — for example an overloaded_error partway through. A client that only checks the HTTP status code at connection time misses this: the initial connection can return 200 and start streaming normally, then fail partway through with a distinct SSE error event. Robust streaming code watches for the error event type throughout the stream, not just at connection time, and is prepared to retry the whole request from scratch since there's no way to resume a partially-streamed generation.
The SDK's stream helper vs the raw event iterator
Official SDKs provide a higher-level streaming helper that emits parsed, semantic events (a callback per text delta, a callback per completed content block) and exposes a method to await the fully accumulated final message once the stream ends, so most application code never has to hand-roll the delta-accumulation logic described above. Reaching for the raw SSE event iterator directly is still worth knowing how to do — some event details, like the exact block index or a raw ping, aren't always surfaced by the convenience layer, and in a language without an official SDK the raw lifecycle is all you have. Understanding the raw event sequence is also what lets you reason correctly about what the helper is doing under the hood, which is the version of streaming knowledge the exam actually tests, even if your production code uses the helper.
Usage accounting during a stream
input_tokens is known before generation starts and appears in the initial message_start snapshot, since the full input has already been processed by the time any output streams back. output_tokens, by contrast, only reaches its final value on message_delta, because generation isn't complete until then — reading it from an earlier point in the stream gets a partial or stale count. Cost itself does not change because a request was streamed: streaming affects only how the response is delivered to the client, not how many tokens are processed or produced, so there is no price premium or discount tied to stream: true versus an equivalent blocking call.
Key concept
A dropped connection mid-stream is not resumable from where it left off — there is no cursor or offset you can hand back to the API to continue a partial generation. The correct recovery is a fresh request from scratch, which is also why idempotency and retry discipline (Lesson 1.8) matter even more for streaming clients than for simple blocking calls.