# The messages APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition →: your first real calls
The chat window is where you learned Claude; the Messages APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition → is where you put it to work. Same model, no UI. You send a structured request, you get back structured output, and you do it from your own code, on your own schedule, inside your own product.
You have made a generic "first call" before. So let's skip the ceremony and go straight to what is specific to Claude: how the request is shaped, why the
systemEvery call to the Messages APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition → is built from a few required parts:
role (user or assistant) and content.That last point is the first thing that trips people coming from other APIs. In the Messages APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition →, the system prompt is not a message with role: "system". It is its own field on the request. Anthropic models are trained around this structure, and keeping standing instructions in system rather than stuffing them into a user turn measurably improves how reliably Claude follows them.
A tokentokenA token is the basic unit of text that language models process, often a word fragment, whole word, or punctuation mark rather than a single character.View full definition →, as a reminder, is the chunk of text the model reads and writes in (roughly a few characters). You pay per tokentokenA token is the basic unit of text that language models process, often a word fragment, whole word, or punctuation mark rather than a single character.View full definition → in and per tokentokenA token is the basic unit of text that language models process, often a word fragment, whole word, or punctuation mark rather than a single character.View full definition → out, so max_tokens is also a cost control.
Here is a complete, runnable call. Install the SDK with pip install anthropic and set your key as the ANTHROPIC_API_KEY environment variable first.
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY from the environment
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=1024,
system="You are a precise release-notes editor. Reply in tight bullet points.",
messages=[
{
"role": "user",
"content": "Summarize: we shipped SSO, fixed a billing bug, and removed the legacy export.",
}
],
)
print(response.content[0].text)Walk through what comes back. The response is an object, not a raw string. Its content is a list of content blocks, because a single reply can contain more than one kind of block (text, and later, tool-use requests). For a plain text answer you read response.content[0].text. You also get response.usage with input and output tokentokenA token is the basic unit of text that language models process, often a word fragment, whole word, or punctuation mark rather than a single character.View full definition → counts, and response.stop_reason, which tells you *why* Claude stopped: end_turn means it finished naturally, max_tokens means it hit your ceiling and got cut off. Always check stop_reason in production. A truncated answer that you treated as complete is a silent bug.
Check the current model names and parameters in the official Messages API reference before you ship, since model IDs roll forward over time.
The APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition → is stateless. Claude does not remember your last call. *You* hold the conversation by appending each turn to the messages list and sending the whole thing back.
A multi-turn exchange is just an alternating list:
messages = [
{"role": "user", "content": "What's a good index for a time-series table?"},
{"role": "assistant", "content": "Start with a composite index on (device_id, ts)."},
{"role": "user", "content": "Why that order and not (ts, device_id)?"},
]Two rules to internalize. First, turns must alternate user and assistant; you cannot send two user turns in a row. Second, you can seed the assistant's reply by ending your messages list on an assistant turn with partial content. Claude will continue from exactly where you left it. This trick, called prefilling, is genuinely useful: prefill with { to force JSON output, or with Here is the answer in three bullets: to lock the format. It is a Claude-specific lever that the chat UI never exposes to you.
When Claude is writing a long answer, you do not want to wait for the entire thing before showing anything. Streaming sends the response back in pieces as they are generated, so text appears word by word, the way it does in the Claude app.
Flip one argument and iterate:
with client.messages.stream(
model="claude-sonnet-4-5",
max_tokens=2048,
system="You are a technical writer. Be concrete.",
messages=[{"role": "user", "content": "Explain database connection pooling."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message()
print("\n\nTokens used:", final.usage.output_tokens)The stream() method returns a context manager (the with block), which guarantees the connection closes cleanly even if something fails mid-stream. The text_stream helper hands you just the text deltas, which is what you usually want for a UI. When the loop ends, get_final_message() reassembles the complete response so you still get usage and stop_reason.
Stream whenever a reply might be long or whenever a human is watching it arrive. For short background jobs where nothing is waiting on the output, the plain create() call is simpler and just as fast overall.
A few behaviors are worth knowing before you build on them.
System prompts carry real weight. Because of where system sits in the request, persistent instructions there are followed more consistently than the same text buried in a user message. Put the durable stuff (role, output format, hard constraints) in system, and the per-request task in the user turn.
Long context is a feature, not just a number. Claude models support large context windows, big enough to drop in whole documents, long transcripts, or a sizable chunk of a codebase. Practically, that means you can often pass source material directly instead of building retrieval for it. Prices and exact window sizes shift, so confirm the current figures in the docs rather than memorizing them.
The same API powers tools and agents. Everything you will build later (tool use, the connectors that the Claude apps expose, MCP servers, and the Claude Agent SDK) sits on top of this exact messages.create call. Tool use is just additional content block types flowing through the same request and response shape you already understand. Learn this surface well and the rest of the Claude path becomes incremental.
Knowledge check
1. In the Messages API, how is the system prompt provided in a request?
2. What does the max_tokens parameter actually control?
3. Among Claude's model families, which is described as the everyday workhorse balancing capability and cost?
4. Select ALL correct answers about the required and important components of a Claude Messages API request.
Sélectionnez toutes les réponses correctes.
5. Select ALL correct answers about tokens and roles in the Messages API.
Sélectionnez toutes les réponses correctes.
Real calls fail sometimes. The two you will meet first:
ANTHROPIC_API_KEY is missing, wrong, or not loaded into the environment. Print the variable (not the key itself) to confirm your process can see it.The SDK already retries certain failures with exponential backoff, but you should still wrap calls and handle the cases the SDK gives up on:
import anthropic
client = anthropic.Anthropic()
try:
response = client.messages.create(
model="claude-sonnet-4-5",
max_tokens=512,
messages=[{"role": "user", "content": "One sentence on idempotency."}],
)
print(response.content[0].text)
except anthropic.RateLimitError:
print("Rate limited. Slow down and retry with backoff.")
except anthropic.APIStatusError as exc:
print(f"API error {exc.status_code}: {exc.message}")Catch RateLimitError specifically when you want custom backoff, and fall back to APIStatusError for everything else with a non-success status. This is the difference between a script that dies on the first hiccup and a service that survives a busy afternoon.
One operational note, because it bites people on day one. Your APIAPIApplication Programming Interface: a standardised interface that lets applications communicate and exchange data without knowing each other's internal workings.View full definition → key is a secret with billing attached. Never hardcode it in source, never commit it, never ship it inside a browser app where users can read it. Keep it in an environment variable or a secrets manager, and let the SDK read it automatically. The anthropic.Anthropic() constructor picks up ANTHROPIC_API_KEY with no argument, which is exactly why every snippet above leaves it implicit. If you need browser-side calls, route them through a small backend that holds the key, never the client.
You can generate and rotate keys in the Anthropic Console, and the SDK source lives at github.com/anthropics if you want to read how the retries and streaming are implemented.
max_tokens looks complete but isn't, and tokentokenA token is the basic unit of text that language models process, often a word fragment, whole word, or punctuation mark rather than a single character.View full definition → counts are your cost and budget signal.messagesmessages.stream() and the text_stream helper for long or user-facing replies, and create() for silent background jobs.messages.create request and response shape you just learned.