I got the Claude API working in about ten minutes, just following Anthropic's Get Started guide and copying the code as I went. A few lines of Python, a prompt, a reply.
Done.
Then I printed the reply to see what I'd actually gotten back:
print(message.content)
[TextBlock(citations=None, text='Here are some...', type='text')]
Why is it a list? I asked one question. I thought I'd just get an answer as plain text.
Here's what I eventually understood: client.messages.create() is a wrapper. The Messages API itself does one thing — you send it JSON, it sends JSON back. The Python method just builds that JSON, posts it over HTTP, and turns the reply back into Python objects.
So the call I wrote is really this request:
{
"model": "claude-opus-4-8",
"max_tokens": 1000,
"messages": [
{ "role": "user", "content": "What should I search for..." }
]
}
And the server hands back this response:
{
"role": "assistant",
"content": [
{ "type": "text", "text": "Here are some search strategies..." }
],
"stop_reason": "end_turn",
"usage": { "input_tokens": 25, "output_tokens": 530 }
}
(The real response has a few more fields -- cache and token details -- but I've trimmed it down to the parts that matter here.)
Look at content on both sides. It's a list of typed blocks.
When I wrote "content": "What should I search for..." as a plain string in Python, that was just shorthand -- underneath, it's one text block in a list.
That's the whole answer to "why is it a list?" The response wasn't being weird. "content" is always a list of blocks, going out and coming back.
The string form just hides it on the way out.
Top comments (0)