Workshop · the Messages API
The Messages API, in the open
Every feature of Claude's API is an option on one endpoint, POST /v1/messages. Set the options, watch the exact request leave, see what can and cannot be observed before the first token, then read the answer three ways: the raw bytes, the content blocks they build, and the message they add up to. Nothing here is simulated. Live runs go through this site's server to the real API, and recorded runs are saved copies of live ones.
Watch for: One text block. Watch message_start carry the input tokens before a word is written, then text_delta frames, then message_delta with the final output count.
1 · Compose
What the API will say
Omitted thinking on Opus 5 means adaptive: it may think before answering.
2 · On the wire
POST /v1/messages HTTP/1.1
Draft body: hover an option to find it
{"model": "claude-opus-5","max_tokens": 1024,"stream": true,"messages": [{"role": "user","content": "In two sentences: what does a three-layer shell jacket do that a two-layer one doesn't?"}],"output_config": {"effort": "low"}}
Send the request, or replay a recorded run, and everything below fills in as the bytes arrive.
3 · What happened between here and the model
Nothing sent yet.
4 · What came back
The stream appears here.
Four things to take from this page
The API is stateless.
Turn 2 carries turn 1 in messages. Nothing is remembered server-side except a cache, and a cache only matches a byte-identical prefix.
Usage arrives first.
message_start reports input and cache tokens before a word is written. That is how a stream cut off halfway can still be billed correctly.
Parse at the block's end.
Tool input streams as JSON fragments that do not parse until content_block_stop. Accumulate, then parse once.
A 400 is documentation.
It arrives before generation, costs nothing and names the rule. Streaming errors are different: they arrive after a 200, as an error event. Lab 4 covers both.