Messages API Intro

Su Suriya Ravichandran Updated 10 Nov 2026
8 min read ·Lesson 21 of 200

What the Messages API Is

The Messages API is the main way to interact with Claude programmatically. You send a list of conversation messages, and Claude returns the next message in that conversation.

POST https://api.anthropic.com/v1/messages

In the Python SDK, it is the client.messages resource:

message = client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello, Claude"}],
)

Almost every feature in this tutorial is part of the Messages API, controlled by request parameters:

FeatureHow it is enabled in the Messages API
ConversationsSending earlier turns in messages
System promptsThe system parameter
Streamingclient.messages.stream(...) or stream=True
Tool useThe tools parameter
Images and PDFsImage and document blocks in messages
ThinkingThe thinking parameter
Effort and structured outputThe output_config parameter
Prompt cachingcache_control markers

Lessons 11–20 already used the Messages API for single requests. This section (Lessons 21–30) builds a complete understanding of it: its design, its message structure, roles, and multi-turn conversations.


The Core Idea: Messages In, Message Out

The Messages API models every interaction as a conversation:

Input:   [user] → [assistant] → [user] → … → [user]
                                                  │
                                                  ▼
Output:                                 the next [assistant] message
  • Input: a list of alternating user and assistant messages, ending with a user message.
  • Output: one new assistant message, the Message object you have been reading since Lesson 14.

Why this design: a single question is simply a conversation with one turn. A chatbot is the same request with more turns. A tool workflow is a conversation in which some turns contain tool calls and tool results. One consistent structure covers all of these cases. Once you understand messages and roles, every advanced feature fits into the same model.


Statelessness

The Messages API is stateless: it does not remember previous requests. Every request must include all the context Claude needs, including earlier turns of the conversation.

# Request 1
client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "My favorite language is Python."}],
)

# Request 2: Claude does NOT know about request 1
client.messages.create(
    model="claude-opus-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "What is my favorite language?"}],
)

To give Claude memory of a conversation, your application keeps the history and sends it each time (Lesson 24).

Earlier turns do not have to come from Claude. The API accepts synthetic assistant messages that your code writes. That is useful for examples, tests, and controlled conversation setups (Lesson 23).

Note: The documentation also describes message threads (beta), in which the API keeps the conversation so that later requests send only new messages. A thread expires 5 minutes after its last request. This tutorial uses the standard stateless approach, which works everywhere and gives you full control.


Anatomy of a Request

A request combines required and optional parameters.

Required Parameters

ParameterTypePurposeLesson
modelstrWhich Claude model answers12
max_tokensintUpper limit on generated tokens, including thinking13
messageslistThe conversation so far, ending with a user message18, 23–25

Common Optional Parameters

ParameterPurposeLesson
systemInstructions, role, and rules for the whole conversation17, 32
stop_sequencesCustom strings that stop generation48
metadataRequest metadata, such as {"user_id": "..."} for an opaque end-user identifier179
tools, tool_choiceTools Claude may call, and how it should choose81–90
thinkingThinking configuration, such as summarized thinking display151–153
output_configOutput settings such as effort and structured-output format13, 101–110
streamReceive the response incrementally51–60

You do not need to learn all of these now. The important point is that the same endpoint handles everything from a simple greeting to a multi-tool agent, and new capabilities are added as new parameters.

Request Options That Are Not API Parameters

The SDK also accepts a few per-request options that control how the request is sent, not what Claude does:

OptionPurpose
timeoutTimeout for this request (Lesson 10)
extra_headersAdditional HTTP headers, such as anthropic-workspace-id (Lesson 6)
extra_bodyAdditional raw JSON fields for features the SDK version does not type yet

Anatomy of a Response

The response is a Message object (Lesson 14):

FieldMeaning
idUnique message ID
roleAlways "assistant"
modelThe model that answered
contentA list of content blocks: text, thinking, tool use, and others (Lesson 16)
stop_reason / stop_detailsWhy generation ended (Lesson 20)
usageToken counts for billing and monitoring (Lesson 30)

The response is the next assistant turn. In a conversation, you append it to your history and add the next user message (Lessons 24–25).


The Messages API has companion endpoints that share the same request format:

SDK callPurpose
client.messages.create(...)Generate a response
client.messages.stream(...)Generate a response with streaming helpers
client.messages.count_tokens(...)Count the input tokens of a request without generating anything (Lesson 46)
client.messages.batches.create(...)Submit many Messages requests for asynchronous processing at reduced cost (Lessons 131–140)

Because they share the same structure, a request you build for create() can be counted with count_tokens() or submitted in a batch with very few changes.


Messages API vs. Other Options

OptionWhat it isUse it for
Messages APIDirect access to Claude models with full control over each requestCustom applications, chatbots, pipelines, and your own agent loops
Claude Managed AgentsA pre-built, configurable agent harness that runs in Anthropic's managed infrastructureLong-running tasks and asynchronous agent work, without building the loop yourself
Text Completions APIA legacy API that predates the Messages APINothing new: do not use it for new projects

This tutorial focuses on the Messages API. It is the foundation for everything else, including tool use and agents.


Practical Example: Exploring the Request Parameters

This script sends variations of a request to show how optional parameters change the result, while the core structure stays the same.

"""explore_messages_api.py: see how optional parameters shape a response."""

from anthropic import Anthropic
from anthropic.types import Message

client = Anthropic()

BASE_REQUEST = {
    "model": "claude-opus-5-5",
    "max_tokens": 2048,
    "messages": [{"role": "user", "content": "List some uses of Python, one per line."}],
}

VARIATIONS = {
    "plain": {},
    "with system prompt": {
        "system": "Answer in exactly three short lines, no extra text.",
    },
    "with stop sequence": {
        "system": "Number each line, starting at 1.",
        "stop_sequences": ["3."],
    },
    "with low effort": {
        "output_config": {"effort": "low"},
    },
}


def get_text(message: Message) -> str:
    return "".join(block.text for block in message.content if block.type == "text")


for name, extra in VARIATIONS.items():
    response = client.messages.create(**BASE_REQUEST, **extra)
    print(f"=== {name} ===")
    print(get_text(response).strip())
    print(
        f"[stop_reason={response.stop_reason}, stop_sequence={response.stop_sequence}, "
        f"output_tokens={response.usage.output_tokens}]\n"
    )

Example output (shortened; wording varies):

=== plain ===
Web development (Django, Flask, FastAPI)
Data analysis and visualization
Machine learning and AI
...
[stop_reason=end_turn, stop_sequence=None, output_tokens=212]

=== with system prompt ===
Web development
Data science
Automation scripts
[stop_reason=end_turn, stop_sequence=None, output_tokens=64]

=== with stop sequence ===
1. Web development
2. Data analysis
[stop_reason=stop_sequence, stop_sequence=3., output_tokens=41]

=== with low effort ===
Web development
Data analysis
Automation
...
[stop_reason=end_turn, stop_sequence=None, output_tokens=58]

How It Works

  • BASE_REQUEST holds the three required parameters that every variation shares.
  • VARIATIONS maps a label to the optional parameters to add. "plain": {} adds nothing, which gives a baseline.
  • client.messages.create(**BASE_REQUEST, **extra) unpacks both dictionaries into keyword arguments. This pattern keeps the shared request in one place. Lesson 22 uses it extensively.
  • The system prompt variation shows how instructions shape format and length.
  • The stop sequence variation stops as soon as Claude writes 3.. The response reports stop_reason=stop_sequence and which sequence matched. The matched text itself is not included in the output.
  • The low-effort variation usually uses fewer output tokens, because the model thinks less.

Common Mistakes

Expecting the API to Remember Conversations

Fix: send the full relevant history with every request (Lesson 24).

Ending messages with an Assistant Turn

What happens: a 400 error on current models, which do not support prefill.

Fix: always end with a user message (Lesson 18).

Using Old Examples with Removed Parameters

What happens: code copied from older tutorials sends temperature, top_p, or top_k, which API version 2026-10-21 rejects (Lesson 19).

Fix: remove them, and use prompting, structured outputs, and validation instead.

Creating Requests Without Checking the Response Type

What happens: code assumes every response is a finished text answer.

Fix: handle content blocks by type (Lesson 16) and check stop reasons (Lesson 20).


Best Practices

  • Think in conversations: every request is a conversation, even a single question.
  • Keep shared request settings in one place and add per-request variations, as in the example.
  • Learn the required parameters first (model, max_tokens, messages), then add optional features one at a time.
  • Use count_tokens() to estimate the cost of large requests before sending them.
  • Prefer the Messages API for anything you build with fine-grained control. Consider Managed Agents for long-running autonomous tasks.

Exercise

  1. Add a variation named "with metadata" that passes metadata={"user_id": "student-42"}. Does the response change? Why might metadata still be useful?
  2. Add a variation that combines a system prompt and low effort. Compare its output_tokens with the other variations.
  3. Write two separate requests that demonstrate statelessness: tell Claude a fact in the first, and ask about it in the second. Then combine both turns into one request (with a short assistant reply in between) and compare.
Show answers
  1. The response content does not change, because metadata is not shown to the model as instructions. The user_id is an opaque identifier that helps associate requests with your end users, for example when investigating abuse reports. Never put names, emails, or other personal data in it. Use an internal ID instead.

  2. Example variation:

"system + low effort": {
    "system": "Answer in exactly three short lines, no extra text.",
    "output_config": {"effort": "low"},
},

It usually produces the fewest output tokens, because both the answer and the thinking are shorter.

  1. In separate requests, the second answer cannot know the fact. In the combined request:
messages = [
    {"role": "user", "content": "My favorite language is Python."},
    {"role": "assistant", "content": "Great choice!"},
    {"role": "user", "content": "What is my favorite language?"},
]

Claude answers "Python", because the earlier turns are part of the input.

0 Comments

Reviewed before they appear

No comments yet.

Anthropic SDK Using Python
Anthropic SDK Intro Claude API Intro SDK Requirements Install Anthropic SDK Upgrade the SDK Create an API Key Set API Keys Use Environment Variables Import Anthropic Create a Client Send Your First Message Choose a Claude Model Set Max Tokens Read a Response Print Response Text Understand Message Blocks Use System Prompts Send User Messages Set Temperature Handle Stop Reasons Messages API Intro Create Messages Use Message Roles Send Conversation History Continue a Conversation Build a Chat Loop Reset Chat History Use Multiple Turns Inspect Message IDs Read Usage Data Write Clear Prompts Set a System Prompt Add Context to Prompts Use Prompt Templates Add Examples to Prompts Request JSON Output Use XML Tags Control Response Length Improve Prompt Quality Avoid Prompt Injection Read Text Blocks Read Content Blocks Check Stop Reasons Count Input Tokens Count Output Tokens Count Tokens Before Sending Limit Output Tokens Use Stop Sequences Read Request IDs Parse API Responses Streaming Intro Stream Text Output Use Stream Events Use Stream Helpers Get Final Messages Stream Async Responses Handle Stream Errors Build a Live Chat Stream Long Responses Close Streams Safely Build a Chatbot Keep Chat History Manage Chat Sessions Add Chat Memory Build a CLI Chatbot Build a Web Chatbot Use Flask with Claude Use FastAPI with Claude Return JSON from an API Add Chat Error Messages Async SDK Intro Create an Async Client Send Async Messages Use asyncio Run Parallel Requests Stream Async Text Handle Async Errors Set Async Timeouts Close Async Clients Choose Sync or Async Tool Use Intro Define a Tool Create Tool Schemas Send Tools to Claude Read Tool Calls Run Python Tools Return Tool Results Continue After Tool Use Control Tool Choice Handle Tool Errors Use the beta_tool Decorator Create a Tool Runner Add Tool Docstrings Validate Tool Inputs Use Multiple Tools Limit Tool Calls Log Tool Activity Build a Weather Tool Build a Search Tool Build a Calculator Tool Structured Output Intro Request JSON Data Validate JSON Output Use Pydantic Models Handle Invalid JSON Extract Fields from Text Generate Typed Data Use Image URLs Send Base64 Images Read PDFs with Claude Use Output Schemas Build Data Extraction Test Structured Responses Send Image Inputs Upload Files Use File IDs Process Text Files Summarize Documents Extract Table Data Handle File Errors Read Cache Usage Reduce Repeated Input Costs Debug Cache Misses Prompt Caching Intro Enable Prompt Caching Cache System Prompts Cache Long Context Test Cache Performance Use Cache Breakpoints Cache Best Practices Message Batches Intro Create a Message Batch Set Batch IDs Check Batch Status List Message Batches Get Batch Results Process Batch Outputs Handle Failed Batch Items Use Batches for Bulk Tasks Compare Batches and Requests Handle API Errors Handle Rate Limits Retry Failed Requests Set Request Timeouts Handle Network Errors Use Exponential Backoff Build Reliable API Calls Use Extended Thinking Log API Errors Track Request IDs Paginate API Results Set Thinking Budgets Read Thinking Blocks Use Tool Search Use Web Search Tools Use Computer Tools Use Citations Use Token Counting Read Raw Responses Set Custom Headers Use Claude on AWS Bedrock Use Claude on Vertex AI Use Claude on Microsoft Foundry Configure Cloud Credentials Choose a Cloud Provider Compare API Integrations Configure Provider Clients Handle Cloud Errors Use Cloud SDK Extras Deploy Cloud Apps Protect API Keys Use a .env File Ignore Secrets in Git Validate User Input Reduce Prompt Injection Limit Tool Permissions Avoid Unsafe Tool Calls Sanitize Tool Results Set Usage Limits Review Security Logs Test SDK Functions Mock API Responses Test Error Handling Test Streaming Code Measure Token Usage Track API Costs Configure Logging Deploy with Docker Deploy a FastAPI App Monitor Production Apps Build a Claude Chatbot Build a Text Summarizer Build a Code Explainer Build a JSON Extractor Build a PDF Assistant Build a Streaming Chat App Build a Tool-Calling Agent Build a Batch Processor Build a Research Assistant Build a Claude API Dashboard
Ask about this post
AI Ask about this post

Ask questions about Messages API Intro and get answers drawn from it.

Signed-in readers only.