Anthropic Claude API Complete Guide 2026 — Build with Claude Opus, Sonnet and Haiku
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 anthropicimport 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/sdkBasic 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 Case | Recommended Model | Reason |
|---|---|---|
| Complex analysis, long documents | claude-opus-4-6 | Highest intelligence and reasoning |
| Coding, general-purpose tasks | claude-sonnet-4-6 | Best speed-quality balance |
| High-volume, low-latency responses | claude-haiku-4-5-20251001 | Fastest and cheapest |
| Math and multi-step reasoning | claude-sonnet-4-6 with thinking | Extended reasoning mode |
| Simple classification, routing | claude-haiku-4-5-20251001 | Very 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_tokenshigh enough — Claude stops atmax_tokens. If responses are truncated, increase this value. For long documents, 4096 or 8192 is common. - Ignoring
stop_reason— Always checkresponse.stop_reason. If it ismax_tokensinstead ofend_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_useblock, your code executes the function, and you return atool_result— this cycle repeats untilstop_reasonisend_turn. - Always check
response.stop_reason— a value ofmax_tokensindicates 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