Messages API Basics
7 examples to get you started with the Messages API - 5 basic and 2 intermediate.
Prerequisites
- Install the official SDK:
pip install anthropic. - Set an API key in your environment:
export ANTHROPIC_API_KEY=sk-ant-...(or constructanthropic.Anthropic(api_key=...)directly). - All examples use
claude-opus-4-8; swap inclaude-sonnet-5orclaude-haiku-4-5if you want a different speed/cost tradeoff.
Basic Examples
1. A Single-Turn Request
The smallest possible call: one user message, no history.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[
{"role": "user", "content": "What is the capital of France?"},
],
)
print(response.content[0].text)max_tokensis required on every request and caps the length of Claude's reply.response.contentis a list of content blocks; for a plain text reply, the first block's.textholds the answer.- No
systemprompt is required - it's optional, not mandatory.
2. Adding a System Prompt
The system parameter sits outside messages and shapes tone, persona, or constraints for the whole conversation.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system="You are a terse assistant. Answer in one sentence.",
messages=[
{"role": "user", "content": "Why is the sky blue?"},
],
)
print(response.content[0].text)systemis a top-level request parameter, not a message with a role.- It applies to every turn in the conversation, not just the first.
- Keep it stable across requests in the same conversation - changing it mid-conversation affects both behavior and prompt caching.
3. A Multi-Turn Request
Continue a conversation by including Claude's prior reply as an assistant turn before your next question.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "The capital of France is Paris."},
{"role": "user", "content": "What is its population?"},
],
)
print(response.content[0].text)- Roles must strictly alternate
user,assistant,user- the API rejects requests that break this pattern. - The API is stateless: Claude only knows about "Paris" here because it's present in the resent history, not because it remembers the earlier call.
- In practice, you build this array programmatically by appending each response before the next request, rather than hardcoding it.
4. Reading the Response Object
The full Message object carries more than just the reply text - inspect it to build reliable applications.
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Name three programming languages."}],
)
print(response.stop_reason) # why generation stopped, e.g. "end_turn"
print(response.usage.input_tokens, response.usage.output_tokens)
print(response.model) # the model that actually served the responsestop_reasontells you whether Claude finished naturally (end_turn), hit the token cap (max_tokens), or stopped for another reason.usagereports token counts for both the input and the generated output, which is what you're billed on.- Always check
stop_reasonbefore trustingresponse.contentis complete - amax_tokensstop means the reply was cut off.
5. Handling Errors
Network issues, rate limits, and bad requests all raise typed exceptions - catch them explicitly rather than guessing from a bare Exception.
import anthropic
client = anthropic.Anthropic()
try:
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
)
except anthropic.RateLimitError:
print("Rate limited - back off and retry")
except anthropic.APIStatusError as e:
print(f"API error {e.status_code}: {e.message}")- The SDK exposes a distinct exception class per HTTP status (
RateLimitError,NotFoundError,AuthenticationError, and so on). - Catch the most specific exception first, then fall back to the broader
APIStatusErrorfor anything else. - The SDK already retries
429and5xxresponses automatically with backoff, so a caughtRateLimitErrormeans retries were exhausted.
Intermediate Examples
6. Building the Messages Array in a Loop
Most real applications don't hardcode the conversation - they append to a list and resend it on every turn.
import anthropic
client = anthropic.Anthropic()
messages = []
def ask(user_text: str) -> str:
messages.append({"role": "user", "content": user_text})
response = client.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
system="You are a helpful assistant who remembers context within this chat.",
messages=messages,
)
reply_text = response.content[0].text
messages.append({"role": "assistant", "content": response.content})
return reply_text
print(ask("My favorite color is teal."))
print(ask("What's my favorite color?"))- Append the full
response.content(not just the extracted text) as the assistant turn, so any non-text blocks are preserved for later turns. messagesgrows by two entries per exchange: your newuserturn and Claude'sassistantreply.- This is the pattern every multi-turn chat interface is built on, whether it's a CLI loop or a web backend.
7. Streaming a Response
For longer replies, stream tokens as they're generated instead of waiting for the full response.
import anthropic
client = anthropic.Anthropic()
with client.messages.stream(
model="claude-opus-4-8",
max_tokens=2048,
messages=[{"role": "user", "content": "Write a short poem about the ocean."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final_message = stream.get_final_message()
print("\n\nStop reason:", final_message.stop_reason)client.messages.stream()returns a context manager;stream.text_streamyields incremental text chunks as they arrive.- Call
stream.get_final_message()after the loop to get the completeMessageobject, includingusageandstop_reason. - Streaming is recommended for any request where
max_tokensis large, since non-streaming requests risk hitting client-side HTTP timeouts.
Related: Understanding Roles and Turns in the Messages API - the conceptual model behind these examples | Building Multi-Turn Conversations with the Messages Array - a deeper look at managing conversation state
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.