Code windows and terminal icons with Python and TypeScript examples for the Claude API
Code Snippets
Intermediate
19 min read Updated

Claude API Snippets: Python & TypeScript Examples (2026)

Ready-to-use Claude API code snippets in Python and TypeScript. Vision, tool use, streaming, and production patterns. Practical guidance, examples, and tools.

Claude Anthropic Python TypeScript Code Snippets Prompt Caching

Anthropic’s Messages API implements distinct structural conventions for client configuration, message schemas, and streaming event loops. Software engineers integrating Claude must navigate key differences from other frontier providers, including dedicated system parameters, mandatory token ceilings, and explicit cache control breakpoints.

This reference provides 40 production-tested Claude API code snippets spanning Python and TypeScript. Each pattern demonstrates current architectural practices for frontier models in 2026, including Claude Sonnet 5, Claude Opus 5, and Claude Haiku 4.5.

Key Takeaways

  • Claude Sonnet 5 (claude-5-sonnet-20260620) serves as the production baseline for agentic coding and analysis, supporting a 200,000-token context window and up to 16,384 output tokens.
  • The official Claude Python SDK requires Python 3.10+ and httpx2, while the Claude TypeScript SDK (@anthropic-ai/sdk) delivers native TypeScript definitions for Node.js, Bun, and edge runtimes.
  • Anthropic prompt caching reduces repeated input token costs by up to 90% ($0.30 per million tokens on Claude Sonnet 5) and decreases time-to-first-token latency by 80% to 85% for prefixes over 1,024 tokens.
  • Production function calling employs input_schema definitions with optional eager_input_streaming for processing real-time JSON deltas during agentic execution loops.

Quick Setup and Client Authentication

Initializing an Anthropic client requires authenticating with an API key exported to your environment. The client reads ANTHROPIC_API_KEY by default, keeping credentials outside application codebases.

Snippet 1: Install and Import (Python)

pip install anthropic
import anthropic

# Verify package initialization
client = anthropic.Anthropic()

The official Anthropic Python SDK GitHub Repository requires Python 3.10 or later and relies on httpx2 for asynchronous network transports.

Snippet 2: Client Initialization Options (Python)

import os
import anthropic

# Option 1: Implicit environment loading (recommended for production)
client = anthropic.Anthropic()

# Option 2: Explicit configuration with custom timeouts and backoff limits
client = anthropic.Anthropic(
    api_key=os.environ.get("ANTHROPIC_API_KEY"),
    timeout=60.0,
    max_retries=3
)

Configuring a discrete timeout prevents stalled connections when processing large context blocks. Setting max_retries ensures automatic recovery from transient HTTP 429 and 529 responses.

Snippet 3: TypeScript SDK Initialization

npm install @anthropic-ai/sdk
import Anthropic from '@anthropic-ai/sdk';

// Automatic process.env.ANTHROPIC_API_KEY resolution
const client = new Anthropic({
  maxRetries: 3,
  timeout: 60000,
});

The Anthropic TypeScript SDK GitHub Repository delivers full TypeScript declarations for modern JavaScript runtimes, including Node.js, Bun, and Deno.

Basic Message Requests and Frontier Model Selection

The Messages endpoint (/v1/messages) serves as the fundamental communication primitive for all Claude models. Every request requires model, max_tokens, and a messages array.

Model Tier API Model Identifier Context Window Max Output Tokens Input / Output Cost (per 1M) Primary Production Use Case
Claude Sonnet 5 claude-5-sonnet-20260620 200,000 tokens 16,384 tokens $3.00 / $15.00 ($0.30 cached) Flagship agentic coding, multi-turn tool loops, and document analysis
Claude Opus 5 claude-5-opus-20260715 200,000 tokens 16,384 tokens $15.00 / $75.00 ($1.50 cached) Enterprise systems architecture, complex mathematical reasoning, and high-trust validation
Claude Haiku 4.5 claude-4-5-haiku-20251015 200,000 tokens 8,192 tokens $1.00 / $5.00 ($0.10 cached) High-throughput classification, real-time data extraction, and sub-500ms workflows

Snippet 4: Standard Message Request (Python)

When configuring a basic Anthropic Claude API Python example 2026, developers specify the model, max_tokens, and messages parameters:

import anthropic

client = anthropic.Anthropic()

message = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "Explain vector embeddings in two paragraphs."}
    ]
)

# Extract response string from the first content block
print(message.content[0].text)

The API returns a list of content blocks rather than a raw string. Accessing message.content[0].text yields the generated completion. When piping embeddings or retrieval context into Claude, see our vector database code snippets for connecting Pinecone, Weaviate, and ChromaDB.

Snippet 5: Dynamic Frontier Model Router

import anthropic

client = anthropic.Anthropic()

def execute_completion(prompt: str, tier: str = "workhorse") -> str:
    model_map = {
        "workhorse": "claude-5-sonnet-20260620",
        "reasoning": "claude-5-opus-20260715",
        "speed": "claude-4-5-haiku-20251015"
    }
    
    selected_model = model_map.get(tier, "claude-5-sonnet-20260620")
    
    response = client.messages.create(
        model=selected_model,
        max_tokens=2048,
        messages=[{"role": "user", "content": prompt}]
    )
    return response.content[0].text

Routing tasks dynamically balances inference expenditure and speed. High-volume ingestion paths benefit from Haiku, while complex logic runs on Sonnet or Opus.

Snippet 6: Sampling Parameters (Temperature and Top-P)

# Deterministic extraction mode
deterministic_response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=512,
    temperature=0.0,
    messages=[{"role": "user", "content": "Extract invoice items: 2 Apples ($4.00), 1 Milk ($3.50)"}]
)

# Exploratory generation mode
exploratory_response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    temperature=0.8,
    top_p=0.95,
    messages=[{"role": "user", "content": "Brainstorm five unique product concepts for edge AI."}]
)

Claude restricts temperature to the range of 0.0 to 1.0. For deep architectural guidance on selecting sampling parameters, consult our sampling parameters guide for temperature and top-p.

Snippet 7: Reading Token Usage and Stop Reasons

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Summarize the ACID properties of relational databases."}]
)

print(f"Stop Reason: {response.stop_reason}")
print(f"Input Tokens: {response.usage.input_tokens}")
print(f"Output Tokens: {response.usage.output_tokens}")

Inspect response.stop_reason to distinguish normal completions (end_turn) from truncated output (max_tokens) or tool execution requests (tool_use).

System Prompts and Structured Prompt Framing

Anthropic enforces a dedicated top-level system parameter rather than accepting system messages inside the messages list. This structural isolation prioritizes system instructions over conversational inputs.

Snippet 8: Basic Top-Level System Parameter

message = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    system="You are a senior database administrator. Respond exclusively with PostgreSQL DDL statements.",
    messages=[
        {"role": "user", "content": "Create a table for user profiles with UUID primary keys."}
    ]
)

print(message.content[0].text)

The top-level system string applies persistently across all dialogue turns. It retains high attention weight even when conversations extend across dozens of interactions.

Snippet 9: Structured Multi-Section System Instructions

system_instructions = """You are a principal security engineer reviewing pull requests.

Rules:
1. Identify CWE vulnerabilities with their official identifiers.
2. Flag unsanitized SQL queries, command injections, and unsafe deserialization.
3. Provide hardened remediation code blocks using parameterized statements.

Response Format:
- Severity: [Critical|High|Medium|Low]
- Vulnerability: Brief description
- Remediation: Sanitized code replacement"""

message = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=2048,
    system=system_instructions,
    messages=[
        {"role": "user", "content": "Review this query: query = f'SELECT * FROM users WHERE id = {user_id}'"}
    ]
)

Structuring system prompts with markdown sections establishes predictable schema conformity. Model attention maps cleanly to explicit operational rules.

Snippet 10: Multi-Turn Conversation History

conversation_history = [
    {"role": "user", "content": "Initialize an empty queue in Python."},
    {"role": "assistant", "content": "from collections import deque\nqueue = deque()"},
    {"role": "user", "content": "Add item 'TaskA' and pop the first element."}
]

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    system="You are a Python data structures tutor.",
    messages=conversation_history
)

print(response.content[0].text)

Conversations require strict alternation between user and assistant roles. Submitting consecutive messages with the same role results in an API validation error.

Streaming Responses and Real-Time Event Loops

Streaming tokens in real time reduces perceived latency for interactive interfaces. The SDK provides high-level helpers alongside low-level Server-Sent Events (SSE) consumers.

Snippet 11: Text Stream Helper (Python)

Using Claude messages stream establishes a Server-Sent Events connection and processes text deltas:

with client.messages.stream(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Explain event-driven microservices architecture."}]
) as stream:
    for text_chunk in stream.text_stream:
        print(text_chunk, end="", flush=True)

The client.messages.stream context manager opens a managed HTTP connection and releases network handles upon block termination.

Snippet 12: Low-Level Event Loop Inspection

with client.messages.stream(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Write a quicksort implementation in Rust."}]
) as stream:
    for event in stream:
        if event.type == "content_block_delta" and event.delta.type == "text_delta":
            print(event.delta.text, end="", flush=True)
        elif event.type == "message_delta":
            print(f"\nFinal stop reason: {event.delta.stop_reason}")

Direct event handling allows client applications to capture token counts, stop reasons, and content block boundaries alongside the raw text stream.

Snippet 13: Collecting Full Streaming Output

accumulated_text = []

with client.messages.stream(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[{"role": "user", "content": "List five key operational benefits of Kubernetes."}]
) as stream:
    for chunk in stream.text_stream:
        accumulated_text.append(chunk)
        print(chunk, end="", flush=True)

final_message = stream.get_final_message()
print(f"\nTotal output tokens consumed: {final_message.usage.output_tokens}")

Calling stream.get_final_message() provides access to aggregated token metrics and metadata after stream completion.

Tool Use and Deterministic Function Calling

Implementing Anthropic API tool use requires defining an input_schema using JSON Schema conventions. Claude evaluates tool declarations and emits structured JSON payloads when external action is required.

Snippet 14: Defining Tool Schemas

tool_definitions = [
    {
        "name": "lookup_database_record",
        "description": "Retrieve customer record by primary customer ID.",
        "input_schema": {
            "type": "object",
            "properties": {
                "customer_id": {
                    "type": "string",
                    "description": "Unique UUID customer identifier."
                },
                "include_orders": {
                    "type": "boolean",
                    "description": "Include past purchase history."
                }
            },
            "required": ["customer_id"]
        }
    }
]

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    tools=tool_definitions,
    messages=[{"role": "user", "content": "Fetch records for customer UUID 9812-4412 including order history."}]
)

The Anthropic Tool Use Documentation details schema validation protocols and execution patterns. Claude adheres to strict typing defined in the properties map.

Snippet 15: Parsing Tool Invocations

if response.stop_reason == "tool_use":
    for block in response.content:
        if block.type == "tool_use":
            print(f"Tool Requested: {block.name}")
            print(f"Tool Call ID: {block.id}")
            print(f"Tool Parameters: {block.input}")

When response.stop_reason equals tool_use, the model generates a tool_use content block containing the generated arguments.

Snippet 16: Complete Tool Execution Loop

def query_customer_db(customer_id: str, include_orders: bool) -> dict:
    return {"customer_id": customer_id, "status": "active", "tier": "enterprise"}

# Step 1: Initial call triggering tool request
initial_response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    tools=tool_definitions,
    messages=[{"role": "user", "content": "Fetch records for customer UUID 9812-4412."}]
)

# Step 2: Execute backend function and return tool_result
if initial_response.stop_reason == "tool_use":
    tool_block = next(b for b in initial_response.content if b.type == "tool_use")
    result_data = query_customer_db(**tool_block.input)
    
    final_response = client.messages.create(
        model="claude-5-sonnet-20260620",
        max_tokens=1024,
        tools=tool_definitions,
        messages=[
            {"role": "user", "content": "Fetch records for customer UUID 9812-4412."},
            {"role": "assistant", "content": initial_response.content},
            {
                "role": "user",
                "content": [
                    {
                        "type": "tool_result",
                        "tool_use_id": tool_block.id,
                        "content": str(result_data)
                    }
                ]
            }
        ]
    )
    print(final_response.content[0].text)

The conversation must preserve the assistant’s tool_use message followed by a user message with tool_result blocks. For an analysis of tool execution versus protocol standards, review our MCP vs function calling architecture comparison.

Snippet 17: Fine-Grained Tool Streaming

Enabling eager input streaming emits raw input_json_delta fragments before whole-block validation:

tools_with_eager = [
    {
        "name": "generate_report",
        "description": "Stream report parameters directly.",
        "input_schema": {
            "type": "object",
            "properties": {"summary": {"type": "string"}},
            "required": ["summary"]
        },
        "eager_input_streaming": True
    }
]

with client.messages.stream(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    tools=tools_with_eager,
    messages=[{"role": "user", "content": "Generate a quarterly report summary."}]
) as stream:
    for event in stream:
        if event.type == "content_block_delta" and event.delta.type == "input_json_delta":
            print(event.delta.partial_json, end="", flush=True)

Eager tool streaming reduces time-to-first-token latency for large JSON payloads. Applications buffer incoming fragments and deserialize once the content_block_stop event fires.

Multimodal Vision and Document Processing

Claude processes multimodal inputs including images, diagrams, and technical charts. Images can be delivered as base64-encoded strings or accessible remote URLs.

Snippet 18: Base64 Encoded Image Ingestion

import base64
import anthropic

client = anthropic.Anthropic()

def encode_local_image(image_path: str) -> str:
    with open(image_path, "rb") as image_file:
        return base64.standard_b64encode(image_file.read()).decode("utf-8")

encoded_image = encode_local_image("system_architecture.png")

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "base64",
                        "media_type": "image/png",
                        "data": encoded_image
                    }
                },
                {"type": "text", "text": "Analyze this architecture diagram and list potential single points of failure."}
            ]
        }
    ]
)

print(response.content[0].text)

Base64 encoding permits offline ingestion of diagrams and proprietary screenshots. Supported image formats include JPEG, PNG, GIF, and WebP.

Snippet 19: Remote Image Analysis via Direct URL

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "image",
                    "source": {
                        "type": "url",
                        "url": "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg"
                    }
                },
                {"type": "text", "text": "Classify the subject in this image."}
            ]
        }
    ]
)

print(response.content[0].text)

URL sourcing enables Claude to retrieve and process images directly. Ensure URLs remain publicly accessible without requiring session cookies.

Snippet 20: Comparative Multi-Image Analysis

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Identify UI regressions between these two staging screenshots:"},
                {
                    "type": "image",
                    "source": {"type": "base64", "media_type": "image/png", "data": encode_local_image("v1.png")}
                },
                {
                    "type": "image",
                    "source": {"type": "base64", "media_type": "image/png", "data": encode_local_image("v2.png")}
                }
            ]
        }
    ]
)

Submitting multiple image blocks within a single request allows comparative visual debugging. Claude evaluates visual layout shifts, color contrast alterations, and spacing differences.

Prompt Caching and Token Cost Optimization

Anthropic prompt caching reduces repeated input token costs by up to 90% ($0.30 per million tokens on Claude Sonnet 5 vs $3.00 unprompted) and cuts time-to-first-token latency by 80% to 85% for requests exceeding the 1,024-token threshold.

Deploying Claude prompt caching code requires setting explicit cache_control breakpoints:

large_document_context = "..." # Long legal agreement or codebase exceeding 1,024 tokens

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    system=[
        {
            "type": "text",
            "text": "You are a specialized legal analysis engine.",
            "cache_control": {"type": "ephemeral"}
        }
    ],
    messages=[
        {
            "role": "user",
            "content": [
                {
                    "type": "text",
                    "text": large_document_context,
                    "cache_control": {"type": "ephemeral"}
                },
                {"type": "text", "text": "Extract all termination notice requirements."}
            ]
        }
    ]
)

print(f"Cache Creation Tokens: {response.usage.cache_creation_input_tokens}")
print(f"Cache Read Tokens: {response.usage.cache_read_input_tokens}")

Review the Anthropic Prompt Caching Documentation for exact cache lifecycle rules. Cached prefixes maintain a 5-minute ephemeral lifespan and refresh automatically upon subsequent cache hits.

Snippet 22: Message Batches for Asynchronous Workloads

batch_requests = [
    {
        "custom_id": "doc-eval-001",
        "params": {
            "model": "claude-5-sonnet-20260620",
            "max_tokens": 1024,
            "messages": [{"role": "user", "content": "Evaluate document A compliance."}]
        }
    },
    {
        "custom_id": "doc-eval-002",
        "params": {
            "model": "claude-5-sonnet-20260620",
            "max_tokens": 1024,
            "messages": [{"role": "user", "content": "Evaluate document B compliance."}]
        }
    }
]

batch_job = client.messages.batches.create(requests=batch_requests)
print(f"Submitted Batch ID: {batch_job.id}")

The Message Batches endpoint processes high-volume tasks within 24 hours at a 50% discount. This approach provides cost efficiency for batch classification, offline embeddings verification, and backfilling data.

Snippet 23: Accurate Token Counting Before Transmission

text_sample = "Anthropic's tokenization algorithms process multilingual text with high efficiency."

token_count = client.beta.messages.count_tokens(
    model="claude-5-sonnet-20260620",
    messages=[{"role": "user", "content": text_sample}]
)

print(f"Pre-flight Token Count: {token_count.input_tokens}")

Calling count_tokens validates context size client-side before dispatching expensive generation requests. This practice prevents hitting context boundaries during multi-document ingestion.

Advanced Structured Extraction with Pydantic

Generating strict JSON outputs without schema drift is essential for enterprise data pipelines. Combining Pydantic with Anthropic tool definitions produces typed data structures.

Snippet 24: Pydantic Schema Generation

from pydantic import BaseModel, Field
import anthropic

class ServerMetric(BaseModel):
    hostname: str = Field(description="Fully qualified domain name of the host")
    cpu_utilization: float = Field(description="CPU load average between 0.0 and 100.0")
    memory_available_gb: float = Field(description="Remaining free memory in gigabytes")
    active_services: list[str] = Field(description="List of active system daemon names")

schema = ServerMetric.model_json_schema()

tool_spec = {
    "name": "record_server_metric",
    "description": "Record extracted telemetry metrics into the monitoring database.",
    "input_schema": schema
}

The Pydantic JSON Schema Documentation explains how typed Python models convert into standard JSON Schema specifications. This prevents discrepancies between data models and API tool configurations.

Snippet 25: Enforced Tool Extraction (Deterministic JSON)

client = anthropic.Anthropic()

unstructured_log = "Host prod-db-01.internal reported 87.4% CPU load with 4.2 GB free memory running postgresql and redis."

response = client.messages.create(
    model="claude-5-sonnet-20260620",
    max_tokens=1024,
    tools=[tool_spec],
    tool_choice={"type": "tool", "name": "record_server_metric"},
    messages=[{"role": "user", "content": f"Parse this telemetry log: {unstructured_log}"}]
)

tool_call = next(block for block in response.content if block.type == "tool_use")
validated_record = ServerMetric(**tool_call.input)
print(validated_record)

Setting tool_choice={"type": "tool", "name": "record_server_metric"} forces Claude to emit the chosen tool parameters without introductory prose. For high-level orchestration, review our PydanticAI vs LangGraph framework comparison.

TypeScript Implementation Patterns

The Claude TypeScript SDK (@anthropic-ai/sdk) provides fully typed interfaces for server-side runtimes including Node.js, Express, and edge workers.

Snippet 26: Basic TypeScript Chat Handler

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

async function generateTechnicalSummary(codeSnippet: string): Promise<string> {
  const response = await client.messages.create({
    model: 'claude-5-sonnet-20260620',
    max_tokens: 1024,
    messages: [
      { role: 'user', content: `Summarize this TypeScript function:\n${codeSnippet}` }
    ]
  });

  const firstBlock = response.content[0];
  return firstBlock.type === 'text' ? firstBlock.text : '';
}

TypeScript type guards ensure compile-time safety when accessing response blocks. Checking firstBlock.type === 'text' validates the block type before reading its contents.

Snippet 27: Async Streaming in TypeScript

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

async function streamConsoleOutput(prompt: string): Promise<void> {
  const stream = client.messages.stream({
    model: 'claude-5-sonnet-20260620',
    max_tokens: 1024,
    messages: [{ role: 'user', content: prompt }]
  });

  for await (const event of stream) {
    if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
      process.stdout.write(event.delta.text);
    }
  }
}

Iterating over the stream with for await processes incoming SSE chunks asynchronously as they arrive from the Anthropic edge.

Snippet 28: Type-Safe Tool Calling in TypeScript

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic();

const tools: Anthropic.Tool[] = [
  {
    name: 'fetch_weather',
    description: 'Get weather conditions for a coordinates pair.',
    input_schema: {
      type: 'object',
      properties: {
        latitude: { type: 'number' },
        longitude: { type: 'number' }
      },
      required: ['latitude', 'longitude']
    }
  }
];

const message = await client.messages.create({
  model: 'claude-5-sonnet-20260620',
  max_tokens: 1024,
  tools,
  messages: [{ role: 'user', content: 'What is the temperature at 37.7749, -122.4194?' }]
});

if (message.stop_reason === 'tool_use') {
  const toolBlock = message.content.find(
    (block): block is Anthropic.ToolUseBlock => block.type === 'tool_use'
  );
  if (toolBlock) {
    console.log(`Executing tool: ${toolBlock.name} with inputs:`, toolBlock.input);
  }
}

Applying the block is Anthropic.ToolUseBlock type predicate allows TypeScript to narrow the union type cleanly inside execution blocks.

Snippet 29: Express.js Streaming Route Handler

import express, { Request, Response } from 'express';
import Anthropic from '@anthropic-ai/sdk';

const app = express();
app.use(express.json());
const client = new Anthropic();

app.post('/api/generate', async (req: Request, res: Response) => {
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  try {
    const stream = client.messages.stream({
      model: 'claude-5-sonnet-20260620',
      max_tokens: 1024,
      messages: [{ role: 'user', content: req.body.prompt }]
    });

    for await (const chunk of stream) {
      if (chunk.type === 'content_block_delta' && chunk.delta.type === 'text_delta') {
        res.write(`data: ${JSON.stringify({ text: chunk.delta.text })}\n\n`);
      }
    }
    res.end();
  } catch (error) {
    res.status(500).end();
  }
});

Configuring standard SSE headers enables direct streaming from Node.js microservices to client browser applications with minimal buffer overhead.

Production Resilience, Rate Limits, and Error Handling

Enterprise systems require robust exception handling to maintain availability across network hiccups and quota exhaustion.

Catching an Anthropic rate limit error allows systems to apply exponential backoff:

import time
import random
from anthropic import (
    Anthropic,
    RateLimitError,
    APIConnectionError,
    APIStatusError,
    AuthenticationError
)

client = Anthropic()

def execute_with_jittered_backoff(prompt: str, max_retries: int = 5) -> str:
    for attempt in range(max_retries):
        try:
            response = client.messages.create(
                model="claude-5-sonnet-20260620",
                max_tokens=1024,
                messages=[{"role": "user", "content": prompt}]
            )
            return response.content[0].text
        except RateLimitError as e:
            wait_time = (2 ** attempt) + random.uniform(0.1, 1.0)
            print(f"Rate limited (429). Retrying in {wait_time:.2f}s...")
            time.sleep(wait_time)
        except APIConnectionError:
            print("Network connectivity error. Retrying...")
            time.sleep(2.0)
        except AuthenticationError:
            print("Authentication failed. Check ANTHROPIC_API_KEY credentials.")
            raise
        except APIStatusError as e:
            print(f"HTTP status error: {e.status_code} - {e.message}")
            raise
    raise RuntimeError("Max retry ceiling exceeded.")

Review the Anthropic Console Key Provisioning Guide to manage rate tiers and workspace token limits. Adding full jitter to exponential delays prevents concurrent requests from causing thundering herd problems during spikes.

Snippet 31: Asynchronous Error Handling with AsyncAnthropic

import asyncio
from anthropic import AsyncAnthropic, RateLimitError

async_client = AsyncAnthropic()

async def async_safe_completion(prompt: str) -> str:
    try:
        response = await async_client.messages.create(
            model="claude-5-sonnet-20260620",
            max_tokens=1024,
            messages=[{"role": "user", "content": prompt}]
        )
        return response.content[0].text
    except RateLimitError:
        await asyncio.sleep(2.0)
        return await async_safe_completion(prompt)

In asynchronous event loops, avoid blocking the thread with standard sleep calls. Utilizing asyncio.sleep maintains high throughput across parallel worker tasks.

Production Tool Orchestration and Agent Architecture

For autonomous multi-step reasoning, Anthropic provides the Claude Agent SDK alongside the Messages API to manage agent loops, state compaction, and tool execution.

Snippet 32: Multi-Turn Tool Resolution Loop

import anthropic

client = anthropic.Anthropic()

def run_agentic_loop(initial_prompt: str, available_tools: list, tool_map: dict) -> str:
    messages = [{"role": "user", "content": initial_prompt}]
    
    while True:
        response = client.messages.create(
            model="claude-5-sonnet-20260620",
            max_tokens=2048,
            tools=available_tools,
            messages=messages
        )
        
        if response.stop_reason != "tool_use":
            return response.content[0].text
            
        messages.append({"role": "assistant", "content": response.content})
        
        tool_results = []
        for block in response.content:
            if block.type == "tool_use":
                handler = tool_map.get(block.name)
                output = handler(**block.input) if handler else "Tool not found"
                tool_results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": str(output)
                })
                
        messages.append({"role": "user", "content": tool_results})

This pattern processes multiple tool calls in a single turn. The model inspects the returned results and decides whether to invoke additional tools or emit the final answer.

Claude API vs OpenAI API Architecture Comparison

Architectural differences between the Claude Messages API and OpenAI Chat Completions require careful parameter mapping during code migration.

Feature Parameter OpenAI (GPT-5.6 Sol) Anthropic (Claude Sonnet 5)
System Prompt Placement Embedded in messages array (role: "system") Top-level API parameter (system: "...")
Max Output Limit Optional default (max_completion_tokens) Mandatory parameter (max_tokens)
Tool Declaration tools=[{"type": "function", "function": {...}}] tools=[{"name": "...", "input_schema": {...}}]
Tool Call Identifier tool_calls=[{"id": "...", "type": "function"}] content=[{"type": "tool_use", "id": "..."}]
Tool Response Format {"role": "tool", "tool_call_id": "..."} {"type": "tool_result", "tool_use_id": "..."}
Vision Input Format image_url object inside content list source: {type: "base64", data: "..."} block
Prompt Caching Mode Automated implicit prefix caching Explicit cache_control: {type: "ephemeral"}
Streaming Primitive Line-delimited JSON chunks via SSE Structured SSE content block events

The primary difference lies in the handling of system prompts and token ceilings. Omitting max_tokens triggers a validation error in Claude, whereas OpenAI provides a fallback. For a broader perspective on multi-model architectures, explore our OpenAI vs Claude vs Gemini API developer comparison.

Frequently Asked Questions

What is the primary difference between the Claude API and OpenAI API?

Claude separates system instructions into a top-level parameter and requires an explicit max_tokens specification on every request. In contrast, OpenAI embeds system instructions inside the messages array and provides automatic background prompt caching.

How do you stream response tokens using the Claude Python SDK?

Developers invoke the client.messages.stream context manager to iterate over incoming text_stream fragments or raw content_block_delta events. This pattern automatically handles network connection lifecycle and buffer management.

How does Anthropic prompt caching reduce production API costs?

Prompt caching provides up to a 90% discount on cached input tokens for prompt segments exceeding 1,024 tokens during a 5-minute ephemeral window. This structure drops input pricing from $3.00 to $0.30 per million tokens on Claude Sonnet 5 while cutting first-token latency by up to 85%.

Claude Sonnet 5 (claude-5-sonnet-20260620) is the recommended standard for high-intelligence coding and structured agent workflows. Teams utilize Claude Haiku 4.5 for high-throughput categorization and Claude Opus 5 for complex architectural reasoning.

Claude Anthropic Python TypeScript Code Snippets Prompt Caching

Found this helpful? Share it with others.

Raj avatar

Raj

Founder, AI Agents Kit

Raj is the founder of AI Agents Kit, where he writes hands-on guides on AI agents, agent frameworks, Model Context Protocol (MCP), prompt engineering and developer tooling. He builds and tests the tools he covers and focuses on practical, working examples for developers and teams adopting agentic AI.

AI Agents LLMs Prompt Engineering Python TypeScript