Anthropic Claude API Complete Guide 2026 — Build with Claude Opus, Sonnet and Haiku

Sanjeev SharmaSanjeev Sharma
8 min read

Advertisement

Introduction

Why This Matters

Claude is Anthropic's family of AI models, built with a strong focus on safety, instruction-following, and long-context reasoning. In 2026, Claude models consistently rank at the top of coding, analysis, and reasoning benchmarks, making the Anthropic API a first-choice option for production AI applications.

The model family is tiered for different use cases: Claude Opus delivers maximum intelligence for complex tasks; Claude Sonnet offers the best balance of speed and capability; Claude Haiku is optimized for high-throughput, cost-sensitive workloads. This guide covers every major API feature — from basic text generation to prompt caching, extended thinking, and tool use — with working Python and TypeScript examples throughout.

Setup and Installation

pip install anthropic
import anthropic
 
# Pass key directly or set ANTHROPIC_API_KEY in environment
client = anthropic.Anthropic(api_key="your-api-key")
# TypeScript / Node.js
npm install @anthropic-ai/sdk

Basic Text Generation

# Simple single-turn message
message = client.messages.create(
    model="claude-opus-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Explain quantum computing in simple terms"}
    ]
)
print(message.content[0].text)
 
# With a system prompt
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=2048,
    system="You are an expert Python developer. Always include working code examples.",
    messages=[
        {"role": "user", "content": "How do I implement a binary search tree in Python?"}
    ]
)
 
# Multi-turn conversation
messages = [
    {"role": "user", "content": "What is a REST API?"},
    {"role": "assistant", "content": "A REST API is an architectural style for distributed hypermedia systems..."},
    {"role": "user", "content": "Show me a Python example of calling one"},
]
 
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=messages,
)
print(response.content[0].text)

Streaming Responses

Streaming dramatically improves perceived latency for end users by delivering the first token in under 500ms for most queries.

# Synchronous streaming
with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a detailed explanation of neural networks"}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)
print()
 
# Async streaming with FastAPI
from anthropic import AsyncAnthropic
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
 
async_client = AsyncAnthropic()
app = FastAPI()
 
@app.post("/chat")
async def chat(question: str):
    async def generate():
        async with async_client.messages.stream(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            messages=[{"role": "user", "content": question}],
        ) as stream:
            async for text in stream.text_stream:
                yield f"data: {text}\n\n"
    return StreamingResponse(generate(), media_type="text/event-stream")

Vision: Analyzing Images

Claude Sonnet and Opus support images up to 5MB. Supported formats: JPEG, PNG, GIF, WebP.

import base64
 
# From a public URL
message = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": [
            {
                "type": "image",
                "source": {
                    "type": "url",
                    "url": "https://example.com/chart.png",
                },
            },
            {"type": "text", "text": "Describe this chart and extract all data points"},
        ],
    }],
)
 
# From a local file (base64)
def analyze_image(image_path: str, prompt: str) -> str:
    with open(image_path, "rb") as f:
        image_data = base64.standard_b64encode(f.read()).decode("utf-8")
 
    ext = image_path.rsplit(".", 1)[-1].lower()
    media_types = {
        "jpg": "image/jpeg", "jpeg": "image/jpeg",
        "png": "image/png", "gif": "image/gif", "webp": "image/webp"
    }
 
    message = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=[{
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": media_types.get(ext, "image/jpeg"),
                        "data": image_data,
                    },
                },
                {"type": "text", "text": prompt},
            ],
        }],
    )
    return message.content[0].text
 
result = analyze_image("screenshot.png", "What bugs do you see in this code?")
print(result)

Tool Use (Function Calling)

Tool use lets Claude call external functions — APIs, databases, calculations — and incorporate the results into its response.

import json
 
tools = [
    {
        "name": "get_weather",
        "description": "Get current weather for a location",
        "input_schema": {
            "type": "object",
            "properties": {
                "location": {"type": "string", "description": "City and country"},
                "units": {
                    "type": "string",
                    "enum": ["celsius", "fahrenheit"],
                    "default": "celsius"
                },
            },
            "required": ["location"],
        },
    },
    {
        "name": "search_web",
        "description": "Search the web for current information",
        "input_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string", "description": "Search query"},
            },
            "required": ["query"],
        },
    },
]
 
def get_weather(location: str, units: str = "celsius") -> dict:
    return {"location": location, "temp": 22, "condition": "sunny", "units": units}
 
def search_web(query: str) -> dict:
    return {"results": [f"Top result for: {query}"]}
 
TOOL_FUNCTIONS = {"get_weather": get_weather, "search_web": search_web}
 
def run_with_tools(user_message: str) -> str:
    messages = [{"role": "user", "content": user_message}]
 
    while True:
        response = client.messages.create(
            model="claude-sonnet-4-6",
            max_tokens=1024,
            tools=tools,
            messages=messages,
        )
 
        if response.stop_reason != "tool_use":
            return " ".join(b.text for b in response.content if b.type == "text")
 
        messages.append({"role": "assistant", "content": response.content})
 
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                fn = TOOL_FUNCTIONS.get(block.name)
                result = fn(**block.input) if fn else {"error": f"Unknown tool: {block.name}"}
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": json.dumps(result),
                })
 
        messages.append({"role": "user", "content": tool_results})
 
answer = run_with_tools("What is the weather like in Mumbai right now?")
print(answer)

Prompt Caching

Prompt caching reduces costs by up to 90% when the same large context (system prompt, documents, or few-shot examples) is reused across multiple requests.

long_document = open("large_codebase_context.txt").read()
 
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "You are a helpful assistant analyzing the following document.",
        },
        {
            "type": "text",
            "text": long_document,
            "cache_control": {"type": "ephemeral"},  # Cache this block
        },
    ],
    messages=[{"role": "user", "content": "What are the main security risks in this code?"}],
)
 
# First call: cache_creation_input_tokens > 0 (paid to build cache)
# Subsequent calls: cache_read_input_tokens > 0 (90% cheaper)
print(response.usage)

Prompt caching requires a minimum of 1,024 tokens to cache. The cache is kept for 5 minutes by default with the ephemeral type.

Extended Thinking

Extended thinking allows Claude to reason through complex problems before producing a final answer. It is especially effective for math, multi-step logic, and ambiguous coding tasks.

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=8000,
    thinking={
        "type": "enabled",
        "budget_tokens": 5000,  # Tokens Claude can use for internal reasoning
    },
    messages=[{
        "role": "user",
        "content": "A train leaves Chicago at 60 mph. Another leaves NYC at 80 mph. They are 790 miles apart. When do they meet?"
    }],
)
 
for block in response.content:
    if block.type == "thinking":
        print(f"Reasoning: {block.thinking[:300]}...")
    elif block.type == "text":
        print(f"Answer: {block.text}")

Model Selection Guide

Use CaseRecommended ModelReason
Complex analysis, long documentsclaude-opus-4-6Highest intelligence and reasoning
Coding, general-purpose tasksclaude-sonnet-4-6Best speed-quality balance
High-volume, low-latency responsesclaude-haiku-4-5-20251001Fastest and cheapest
Math and multi-step reasoningclaude-sonnet-4-6 with thinkingExtended reasoning mode
Simple classification, routingclaude-haiku-4-5-20251001Very cost-effective at scale

TypeScript Integration

import Anthropic from "@anthropic-ai/sdk";
 
const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
 
// Basic message
const message = await client.messages.create({
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Hello, Claude!" }],
});
 
const text = message.content[0];
if (text.type === "text") console.log(text.text);
 
// Streaming in Node.js
const stream = await client.messages.stream({
  model: "claude-sonnet-4-6",
  max_tokens: 1024,
  messages: [{ role: "user", content: "Explain async/await in JavaScript" }],
});
 
for await (const event of stream) {
  if (
    event.type === "content_block_delta" &&
    event.delta.type === "text_delta"
  ) {
    process.stdout.write(event.delta.text);
  }
}

Common Mistakes

  • Not setting max_tokens high enough — Claude stops at max_tokens. If responses are truncated, increase this value. For long documents, 4096 or 8192 is common.
  • Ignoring stop_reason — Always check response.stop_reason. If it is max_tokens instead of end_turn, the response is incomplete.
  • Skipping prompt caching for repeated contexts — If your system prompt is more than 1,024 tokens and you call the API repeatedly, you are paying for the same tokens on every request.
  • Using Opus for simple tasks — Opus costs 5x more than Sonnet. Reserve it for tasks where it demonstrably outperforms Sonnet.
  • No retry logic — The Claude API can return 529 (overloaded) or 529-like errors under load. Always wrap calls with exponential backoff.

Best Practices

import anthropic
from tenacity import retry, stop_after_attempt, wait_exponential
 
client = anthropic.Anthropic()
 
@retry(
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=4, max=10),
    reraise=True,
)
def robust_call(messages: list, system: str = "", model: str = "claude-sonnet-4-6") -> str:
    response = client.messages.create(
        model=model,
        max_tokens=2048,
        system=system,
        messages=messages,
    )
    return response.content[0].text
 
# Track cost per request
COSTS_PER_MILLION = {
    "claude-opus-4-6":          {"input": 15.00, "output": 75.00},
    "claude-sonnet-4-6":        {"input": 3.00,  "output": 15.00},
    "claude-haiku-4-5-20251001": {"input": 0.25,  "output": 1.25},
}
 
def estimate_cost(response: anthropic.types.Message, model: str) -> float:
    rates = COSTS_PER_MILLION.get(model, COSTS_PER_MILLION["claude-sonnet-4-6"])
    input_cost  = (response.usage.input_tokens  / 1_000_000) * rates["input"]
    output_cost = (response.usage.output_tokens / 1_000_000) * rates["output"]
    return round(input_cost + output_cost, 6)

Key Takeaways

  • The Claude model family is tiered by capability and cost: Opus for complex reasoning, Sonnet for general use, and Haiku for high-volume low-latency workloads.
  • Prompt caching reduces API costs by up to 90% when large system prompts or documents are reused across requests — it activates at a minimum of 1,024 cached tokens.
  • Extended thinking (budget_tokens) improves accuracy on multi-step math and logic tasks by giving Claude dedicated reasoning time before producing the final answer.
  • Tool use follows a request-response loop: Claude emits a tool_use block, your code executes the function, and you return a tool_result — this cycle repeats until stop_reason is end_turn.
  • Always check response.stop_reason — a value of max_tokens indicates a truncated response, not a completed one.
  • Vision support covers JPEG, PNG, GIF, and WebP up to 5MB; images can be passed as URLs or base64-encoded strings.
  • Production Claude integrations should include retry logic with exponential backoff to handle transient 529 (overloaded) errors gracefully.
  • Start with Sonnet for most tasks, use Haiku when cost is the primary constraint, and upgrade to Opus only when benchmark testing shows a meaningful quality improvement for your specific use case.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading