}

Claude API with Python: Complete Tutorial 2026 (Messages, Streaming, Vision)

Introduction

The Claude API lets you integrate Anthropic's Claude models into your Python applications. This guide covers everything from your first API call to streaming, vision, and tool use.

Installation

pip install anthropic

Set your API key:

export ANTHROPIC_API_KEY="your-api-key-here"

First Message

import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Explain what a REST API is in simple terms."}
    ]
)

print(message.content[0].text)

System Prompts

message = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    system="You are a senior Python developer. Give concise, practical answers with code examples.",
    messages=[
        {"role": "user", "content": "How do I read a CSV file?"}
    ]
)

Streaming Responses

For long responses, streaming shows output in real time:

with client.messages.stream(
    model="claude-opus-4-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a Python function to sort a list of dicts by key."}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Multi-turn Conversations

conversation = []

def chat(user_message):
    conversation.append({"role": "user", "content": user_message})

    response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        messages=conversation
    )

    assistant_message = response.content[0].text
    conversation.append({"role": "assistant", "content": assistant_message})
    return assistant_message

print(chat("What is Python's GIL?"))
print(chat("How does asyncio work around it?"))

Vision: Analyzing Images

import base64
import httpx

# Load image from URL
image_data = base64.standard_b64encode(
    httpx.get("https://upload.wikimedia.org/wikipedia/commons/thumb/4/47/PNG_transparency_demonstration_1.png/280px-PNG_transparency_demonstration_1.png").content
).decode("utf-8")

message = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": image_data,
                    },
                },
                {"type": "text", "text": "What is in this image?"}
            ],
        }
    ],
)
print(message.content[0].text)

Tool Use (Function Calling)

import json

tools = [
    {
        "name": "get_weather",
        "description": "Get the current weather for a city",
        "input_schema": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "The city name"},
                "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
            },
            "required": ["city"]
        }
    }
]

response = client.messages.create(
    model="claude-opus-4-5",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "What's the weather in Berlin?"}]
)

# Check if Claude wants to use a tool
if response.stop_reason == "tool_use":
    tool_use = next(block for block in response.content if block.type == "tool_use")
    print(f"Tool: {tool_use.name}, Input: {tool_use.input}")

    # Execute tool and return result
    tool_result = {"temperature": 18, "condition": "cloudy", "unit": "celsius"}

    final_response = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        tools=tools,
        messages=[
            {"role": "user", "content": "What's the weather in Berlin?"},
            {"role": "assistant", "content": response.content},
            {
                "role": "user",
                "content": [{"type": "tool_result", "tool_use_id": tool_use.id, "content": json.dumps(tool_result)}]
            }
        ]
    )
    print(final_response.content[0].text)

Async Usage

import asyncio
import anthropic

async def main():
    client = anthropic.AsyncAnthropic()

    # Run multiple requests in parallel
    tasks = [
        client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=256,
            messages=[{"role": "user", "content": f"Translate 'hello' to {lang}"}]
        )
        for lang in ["Spanish", "French", "German", "Japanese"]
    ]

    responses = await asyncio.gather(*tasks)
    for resp in responses:
        print(resp.content[0].text)

asyncio.run(main())

Error Handling

import anthropic

client = anthropic.Anthropic()

try:
    message = client.messages.create(
        model="claude-opus-4-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "Hello"}]
    )
except anthropic.APIConnectionError as e:
    print(f"Network error: {e}")
except anthropic.RateLimitError as e:
    print(f"Rate limit hit, retry after a moment")
except anthropic.APIStatusError as e:
    print(f"API error {e.status_code}: {e.message}")

Model Selection and Cost

ModelBest forSpeedCost
claude-opus-4-5Complex reasoning, codingSlowerHigher
claude-sonnet-4-5Balanced tasksMediumMedium
claude-haiku-4-5Simple tasks, high volumeFastLower

Quick Reference

# Basic call
client.messages.create(model="claude-opus-4-5", max_tokens=1024, messages=[...])

# With system prompt
client.messages.create(model=..., system="...", messages=[...])

# Streaming
with client.messages.stream(model=..., messages=[...]) as stream:
    for text in stream.text_stream: print(text, end="")

# Async
client = anthropic.AsyncAnthropic()
await client.messages.create(...)

Leonardo Lazzaro

Software engineer and technical writer. 10+ years experience in DevOps, Python, and Linux systems.

More articles by Leonardo Lazzaro