DS DevShelfHub Projects · AI tools
Cheatsheets / Anthropic API
Cheatsheet · AI frameworks

Anthropic API: Messages, Tool Use, Streaming and Caching Reference Guide

By DevShelfHub

Messages API, system prompts, tool use, streaming, vision, prompt caching, extended thinking, batch — the Claude SDK as a one-page reference for anthropic-python 0.40+ and anthropic-node 0.30+. Covers every request parameter and the beta header pattern for enabling new features.

112 items 8 min Messages Caching Thinking

Start hereQuick start · 6 you’ll reach for daily

Simple callclient.messages.create(model, max_tokens, messages)
System promptsystem="You are …"
Stream tokenswith client.messages.stream(…) as s:
Tool usetools=[{name, input_schema}]
Cache prefixcache_control={"type":"ephemeral"}
Vision{type:"image", source:{…}}

Target versions · paceVersions

Targets: anthropic-python ≥ 0.40 anthropic-node ≥ 0.30 API: Messages (2023-06-01) python ≥ 3.8

All current Claude features live on the Messages API (/v1/messages). The old /v1/complete Text Completions endpoint is legacy — avoid for new code. The SDK reads ANTHROPIC_API_KEY from env. Beta features (prompt-caching, extended-thinking, message-batches) toggle via the anthropic-beta header or SDK helpers like client.beta.messages.create.

Install · envSetup

bash
# Python SDK
pip install anthropic           # ≥ 0.40

# Node / TS SDK
npm install @anthropic-ai/sdk

# env — picked up automatically
export ANTHROPIC_API_KEY=sk-ant-...

# Bedrock / Vertex variants ship in extras
pip install "anthropic[bedrock]"   # AWS Bedrock
pip install "anthropic[vertex]"    # GCP Vertex AI

Where things liveCommon imports

One package, one client. Anthropic() picks up the env var. Bedrock and Vertex are drop-in replacements via separate client classes.

from anthropic import AnthropicSync client. The default.
from anthropic import AsyncAnthropicAsync client. Use in FastAPI / asyncio.
from anthropic import AnthropicBedrockAWS Bedrock backend. Same Messages API surface.
from anthropic import AnthropicVertexGCP Vertex AI backend.
from anthropic import APIError, RateLimitError, BadRequestError, APITimeoutErrorException types worth catching.
from anthropic.types import Message, ContentBlock, ToolUseBlock, TextBlockType hints for response content.
from anthropic.types import MessageStreamEventEvent types for SSE streaming.

Pick the right oneModels

Current generation

claude-opus-4-7Flagship. Best reasoning + coding. Slowest, priciest.
claude-sonnet-4-6Strong default. Balanced cost / quality / speed.
claude-haiku-4-5-20251001Fastest, cheapest. Use for classify / extract / tool routing.

Previous generation

claude-3-5-sonnet-20241022Still strong. Pin if you need stability.
claude-3-5-haiku-20241022Cheap workhorse pre-4.x.
claude-3-opus-20240229Legacy Outclassed by Opus 4.7. Migrate.
claude-2.1, claude-instant-1.2Legacy Retired endpoints. Do not start here.
Date-stamped IDs are pinned forever; bare aliases like claude-sonnet-4-6 point to the newest snapshot of that family. Pin in production.

The one endpointMessages API

Basic call

client.messages.create(model, max_tokens, messages=[…])The single call shape for everything Claude does.
max_tokens=1024Required. No default. Anthropic forces you to set a ceiling.
resp.content[0].textFirst text block. Content is always a list of blocks.
resp.stop_reasonend_turn / tool_use / max_tokens / stop_sequence.
resp.usage.input_tokens, resp.usage.output_tokensBilling. Cached prefix tokens listed separately.
resp.id, resp.modelResponse ID + the exact model snapshot served.

Messages array

[{"role":"user","content":"hi"}]String content shorthand. Equivalent to a single text block.
[{"role":"assistant","content":"…"},{"role":"user","content":"…"}]Multi-turn. Must alternate user / assistant.
content=[{"type":"text","text":"…"}]Explicit block form. Required for vision, tool_result, cache.
messages must start with role=userHard rule. Use system for system prompts.

System prompt

system="You are a tutor."Plain-string system prompt.
system=[{"type":"text","text":"…"}]Block form — required for prompt caching on the system prompt.
system=[{…, "cache_control":{"type":"ephemeral"}}]Cache the system prompt.

Sampling params

temperature=0.0…1.00 for extraction / code, 0.7 for prose. Range is 0–1, not 0–2.
top_p=0.0…1.0Nucleus sampling. Tune temperature OR top_p.
top_k=…Limit to top-K tokens. Rarely needed.
stop_sequences=["END"]Halt on any string. Plural — pass a list.
metadata={"user_id":"u_42"}End-user hash for abuse signals.

Multimodal · tool I/OContent blocks

Both messages and responses use a list of typed blocks. Mixing text + image + tool_use is just a list with more entries.

{"type":"text","text":"…"}Plain text. The default block.
{"type":"image","source":{"type":"base64","media_type":"image/png","data":"…"}}Inline image bytes.
{"type":"image","source":{"type":"url","url":"https://…"}}Image by URL.
{"type":"document","source":{"type":"base64","media_type":"application/pdf","data":"…"}}Native PDF input. Claude reads text + images.
{"type":"tool_use","id":"toolu_…","name":"…","input":{…}}Model output: a tool call.
{"type":"tool_result","tool_use_id":"toolu_…","content":"…"}Your reply to a tool_use, wrapped in role=user.
{"type":"thinking","thinking":"…"}Extended-thinking trace. Read-only on the response side.

Function callingTool use

tools=[{"name":"…","description":"…","input_schema":{…}}]JSON-Schema definition. input_schema, not parameters.
tool_choice={"type":"auto"}Default. Model decides.
tool_choice={"type":"any"}Must call some tool.
tool_choice={"type":"tool","name":"…"}Force a specific tool.
tool_choice={"type":"none"}Disable tools for this call.
disable_parallel_tool_use=TrueInside tool_choice. One tool call per turn.
stop_reason == "tool_use"Signal to run the tool and call again.

Built-in tools

{"type":"computer_20241022","name":"computer", …}Desktop control (mouse, keyboard, screenshot).
{"type":"bash_20241022","name":"bash"}Shell command execution.
{"type":"text_editor_20241022","name":"str_replace_editor"}File-edit tool used by Claude Code.
{"type":"web_search_20250305","name":"web_search"}Server-side web search. Results spliced into the response.

Worked example

python
from anthropic import Anthropic

client = Anthropic()

tools = [{
    "name": "get_weather",
    "description": "Current weather for a city.",
    "input_schema": {
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
}]

resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    tools=tools,
    messages=[{"role": "user", "content": "Weather in Mumbai?"}],
)

# Loop until the model stops requesting tools
while resp.stop_reason == "tool_use":
    tool_use = next(b for b in resp.content if b.type == "tool_use")
    result = {"temp_c": 31, "city": tool_use.input["city"]}

    resp = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        tools=tools,
        messages=[
            {"role": "user", "content": "Weather in Mumbai?"},
            {"role": "assistant", "content": resp.content},
            {"role": "user", "content": [{
                "type": "tool_result",
                "tool_use_id": tool_use.id,
                "content": str(result),
            }]},
        ],
    )

print(resp.content[0].text)

Token-by-tokenStreaming

with client.messages.stream(…) as stream:Preferred Context manager — auto-closes the SSE connection.
for text in stream.text_stream:Iterator of text deltas only. The shortcut.
for event in stream:Iterator of all events (text, tool, message_stop).
stream.get_final_message()Block-wait for the full Message after iterating.
client.messages.create(…, stream=True)Raw iterator. Manual close required.

Event types

message_startOpens with empty message + initial usage.
content_block_start / _delta / _stopOne trio per block. Watch delta.text or delta.partial_json.
message_deltaUpdates stop_reason + final usage.
message_stopStream is done. Safe to read final state.

Worked example

python
from anthropic import Anthropic

client = Anthropic()

# Context-manager form — auto-closes the SSE connection
with client.messages.stream(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Haiku about Mumbai monsoons."}],
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

    final = stream.get_final_message()
    print(f"\n[done · {final.usage.input_tokens}+{final.usage.output_tokens} tokens]")

10% of input costPrompt caching

cache_control={"type":"ephemeral"}Mark a block as cacheable. 5-minute TTL.
cache_control={"type":"ephemeral","ttl":"1h"}1-hour TTL. Premium pricing.
Place on system, tools, or messages blocksLast block with cache_control becomes the cache boundary.
resp.usage.cache_creation_input_tokensTokens billed at write-rate (first call).
resp.usage.cache_read_input_tokensTokens billed at 10% on cache hits.
Up to 4 cache breakpoints per requestChain them for nested reusable prefixes.
Caching is prefix-only. Anything before the marked block must be byte-identical across calls. Reorder a system prompt and the cache invalidates.

Worked example

python
from anthropic import Anthropic

client = Anthropic()

# Mark expensive prefix content as cacheable.
# Anthropic auto-matches on subsequent calls and bills cached input at 10%.
LONG_DOC = open("policy_handbook.md").read()  # ~50k tokens

resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    system=[
        {"type": "text", "text": "You answer using only the handbook below."},
        {
            "type": "text",
            "text": LONG_DOC,
            "cache_control": {"type": "ephemeral"},  # 5-min TTL
        },
    ],
    messages=[{"role": "user", "content": "What's the leave policy?"}],
)

# Watch usage to confirm a cache hit
print(resp.usage.cache_creation_input_tokens)   # > 0 on first call
print(resp.usage.cache_read_input_tokens)       # > 0 on subsequent calls

Reasoning budgetExtended thinking

thinking={"type":"enabled","budget_tokens":4096}Enable for hard problems. Budget ≤ max_tokens.
temperature=1.0 (required with thinking)Can’t combine extended thinking with low temperature.
{"type":"thinking","thinking":"…"}First block of response is the thinking trace.
{"type":"redacted_thinking","data":"…"}Encrypted trace — pass back unchanged on the next turn.
Round-trip thinking blocks in tool loopsDrop them and the model loses its chain. Reflect them in assistant content.

50% off · 24h SLAMessage Batches

client.messages.batches.create(requests=[…])Submit up to 100k requests. Each has a custom_id.
client.messages.batches.retrieve(batch_id)Poll for processing_status.
client.messages.batches.results(batch_id)Stream JSONL results once ended.
client.messages.batches.list()All recent batches for your workspace.
client.messages.batches.cancel(batch_id)Abort in-flight batch.

Production hygieneErrors & retries

Anthropic(api_key=…, max_retries=4, timeout=30.0)Client-level retry + timeout. Defaults are 2 / 600.
client.with_options(timeout=60).messages.create(…)Per-call override without rebuilding the client.
RateLimitError429. Watch retry-after + anthropic-ratelimit-* headers.
BadRequestError400. Malformed messages, schema, or content. Don’t retry.
APITimeoutError, APIConnectionErrorNetwork. Safe to retry with backoff.
OverloadedError529. Anthropic capacity. Backoff hard.
resp.http_headers["request-id"]Pass to support when filing tickets.

Tool-using agent · ~35 linesEnd-to-end · Minimal agent

Hand-rolled tool loop: call Claude, run tool, feed result back, repeat until stop_reason != "tool_use". No framework — just the SDK.

python
from anthropic import Anthropic

client = Anthropic()

tools = [{
    "name": "lookup_order",
    "description": "Find an order by ID.",
    "input_schema": {
        "type": "object",
        "properties": {"order_id": {"type": "string"}},
        "required": ["order_id"],
    },
}]

def run_tool(name: str, args: dict) -> str:
    if name == "lookup_order":
        return f"Order {args['order_id']}: shipped, ETA Tue."
    return "unknown tool"

messages = [{"role": "user", "content": "Where is order ORD-71?"}]

while True:
    resp = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        tools=tools,
        messages=messages,
    )
    messages.append({"role": "assistant", "content": resp.content})

    if resp.stop_reason != "tool_use":
        print(next(b.text for b in resp.content if b.type == "text"))
        break

    tool_results = [
        {
            "type": "tool_result",
            "tool_use_id": b.id,
            "content": run_tool(b.name, b.input),
        }
        for b in resp.content if b.type == "tool_use"
    ]
    messages.append({"role": "user", "content": tool_results})

Best practiceGood to know

Cache long static prefixes. System prompts, knowledge-base context, tool schemas — anything reused across calls. Cached reads are 10% of normal input cost; a 50k-token handbook becomes nearly free after the first hit.
Inspect resp.content as a list, not a string. Tool use, vision answers, and extended thinking all add non-text blocks. Filter by b.type == "text" when you want the prose.
Use Haiku 4.5 for routing. Tool selection, classification, simple extraction don’t need Sonnet/Opus. Drop the latency and cost by tier.

Common trapsWatch out for

max_tokens is required. Forget it and the SDK errors. Set a real ceiling — default to 1024 unless you have a reason.
Tool schema field is input_schema, not parameters. Copy-pasting an OpenAI tool definition won’t parse. Anthropic uses input_schema at the top level — no function wrapper.
Messages must alternate user / assistant and start with user. Two user turns in a row, or starting with assistant, returns a 400. Merge consecutive same-role turns before sending.

Go deeperSee also

Anthropic API FAQ

What is the Anthropic Messages API?

The Messages API (POST /v1/messages) is the primary way to call Claude. You pass a model, max_tokens, and a messages array with alternating user and assistant turns. The API returns a Message object with content blocks and usage stats.

How do I enable tool use with the Claude API?

Pass a tools array to client.messages.create(). Each tool needs a name, description, and input_schema (JSON Schema). When Claude decides to use a tool, it returns a tool_use content block; you call the tool and return the result in a tool_result block.

What is prompt caching in the Anthropic API?

Prompt caching lets you mark a content block with cache_control: {type: 'ephemeral'} so the API caches that prefix for up to 5 minutes. Cached tokens cost 10% of normal input price and reduce latency on repeated calls with the same system prompt or documents.

How do I stream Claude responses?

Use the client.messages.stream() context manager in Python. It yields events including text_delta, content_block_start, and message_stop. Call stream.get_final_message() after the loop to get the complete Message object.

What Claude models are available via the Anthropic API?

Current models include claude-opus-4-8 (most capable), claude-sonnet-4-6 (balanced quality and speed), and claude-haiku-4-5-20251001 (fastest and cheapest). Choose Haiku for classification and routing, Sonnet as a strong default, and Opus for complex reasoning.

Does the Anthropic API support vision and image inputs?

Yes. Pass an image content block with type: image and source set to either base64-encoded data (with media_type) or a URL. Claude supports JPEG, PNG, GIF, and WebP. Vision is available on all current Claude models.