Claude API and SDKs
The Messages API is the single endpoint behind every other Claude product: Claude Code, the claude.ai web app, the desktop apps, and the Agent SDK all call /v1/messages under the hood. This note is the complete reference: every parameter, every response shape, every streaming event, every error code, every rate-limit header, with the official Python and TypeScript SDKs side-by-side. The Go, Java, C#, PHP, and Ruby SDKs follow the same parameter names and shapes (snake_case in Python, camelCase in TS / Java / C# / Go, snake_case in Ruby / PHP) — the section on language-specific quirks at the end calls out the differences.
See also
- claude-models-and-capabilities — model IDs to pass as
model - prompt-caching — uses the same content-block
cache_controlfield documented here - tool-use-and-function-calling — the
tools/tool_use/tool_resultparameter family - vision-and-multimodal —
image/documentcontent blocks - hidden-tricks-and-gotchas — undocumented headers and behaviors
1. Endpoint
POST https://api.anthropic.com/v1/messages
Auxiliary endpoints (same auth, same anthropic-version):
POST /v1/messages/count_tokens— token-count without running inferencePOST /v1/messages/batches— submit a Batches job (see batch-api-and-files-api)GET /v1/messages/batches/{id}/GET /v1/messages/batches/{id}/results— poll / retrievePOST /v1/files/GET /v1/files/{id}/content— Files API (beta)GET /v1/models/GET /v1/models/{id}— Models API
2. Authentication
Per platform.claude.com/docs/en/api/overview:
x-api-key: $ANTHROPIC_API_KEY
anthropic-version: 2023-06-01
content-type: application/json
x-api-keyis case-insensitive in the standard; SDKs useX-Api-Keycapitalization.anthropic-versionis required. The current frozen value is2023-06-01— older clients pinned to legacy strings (2023-01-01) still work but receive the same response schema.- For workspace API keys: the key encodes the workspace; no extra header needed.
- For OAuth/session-token auth (Bedrock / Vertex / Foundry): the cloud SDK injects equivalent credentials.
anthropic-beta header
Comma-separated list of beta feature names. Authoritative enum per platform.claude.com/docs/en/api/files-content (as of 2026-05-25):
message-batches-2024-09-24, prompt-caching-2024-07-31, computer-use-2024-10-22,
computer-use-2025-01-24, pdfs-2024-09-25, token-counting-2024-11-01,
token-efficient-tools-2025-02-19, output-128k-2025-02-19, files-api-2025-04-14,
mcp-client-2025-04-04, mcp-client-2025-11-20, dev-full-thinking-2025-05-14,
interleaved-thinking-2025-05-14, code-execution-2025-05-22,
extended-cache-ttl-2025-04-11, context-1m-2025-08-07,
context-management-2025-06-27, model-context-window-exceeded-2025-08-26,
skills-2025-10-02, fast-mode-2026-02-01, output-300k-2026-03-24,
user-profiles-2026-03-24, advisor-tool-2026-03-01,
managed-agents-2026-04-01, cache-diagnosis-2026-04-07
Compose as needed: anthropic-beta: prompt-caching-2024-07-31,extended-cache-ttl-2025-04-11,computer-use-2025-11-24.
3. Request parameters
3.1 Required
model(string) — see claude-models-and-capabilitiesmessages(array ofMessageParam) — at least one user messagemax_tokens(integer) — max tokens to generate (1 to model-specific max output)
3.2 Common optional
| Param | Type | Default | Notes |
|---|---|---|---|
system | string | TextBlockParam[] | — | System prompt. As an array, each block can carry its own cache_control. |
temperature | number | 1.0 | 0.0 to 1.0. Removed on Opus 4.7 — sampling parameters dropped in favor of effort levels (per Opus 4.7 migration guide). |
top_p | number | — | Nucleus sampling. Same Opus 4.7 caveat. |
top_k | number | — | Same Opus 4.7 caveat. |
stop_sequences | string[] | — | Custom text sequences to stop generation. |
stream | boolean | false | Enable SSE. |
metadata | {user_id: string} | — | For abuse / rate-limit hashing. Do not put PII here. |
tools | ToolUnion[] | — | Tool definitions; see tool-use-and-function-calling. |
tool_choice | ToolChoice | {type: "auto"} | {type: "any" | "auto" | "tool" | "none", name?, disable_parallel_tool_use?} |
thinking | ThinkingConfigParam | — | {type: "enabled", budget_tokens: N, display?: "summarized" | "omitted"} or {type: "adaptive", display?: ...} or {type: "disabled"} |
cache_control | {type: "ephemeral", ttl?: "5m" | "1h"} | — | Top-level cache control (automatic caching). |
output_config | {format: {type: "json_schema", schema: {...}}, effort?: "low" | "medium" | "high" | "xhigh" | "max"} | — | Structured outputs. |
service_tier | "auto" | "standard_only" | "auto" | "standard_only" opts out of Priority Tier. |
inference_geo | string | — | Pin inference to a region (Vertex / Bedrock regional endpoints). |
container | string | — | Reuse a code-execution sandbox container. |
3.3 Message structure
{ "role": "user" | "assistant", "content": string | ContentBlockParam[] }Content block types (per Messages API ref):
{type: "text", text, cache_control?, citations?}{type: "image", source: Base64ImageSource | URLImageSource, cache_control?}{type: "document", source: Base64PDFSource | PlainTextSource | URLPDFSource | ContentBlockSource | FileSource, title?, context?, citations?, cache_control?}{type: "tool_use", id, name, input, caller?, cache_control?}{type: "tool_result", tool_use_id, content?, is_error?, cache_control?}{type: "thinking", thinking, signature}— preserved from prior turns{type: "redacted_thinking", data}— when thinking was scrubbed for safety reasons{type: "search_result", title, source, content: TextBlockParam[], cache_control?}— for grounding (see citations-and-grounding)
3.4 Tool definitions
{
"name": "get_weather",
"description": "Get current weather",
"input_schema": { "type": "object", "properties": {...}, "required": [...] },
"type": "custom",
"cache_control": {"type": "ephemeral", "ttl": "5m"},
"strict": true,
"defer_loading": false,
"allowed_callers": ["direct", "code_execution_20250825", "code_execution_20260120"]
}strict: true forces output to conform to input_schema exactly — see Strict tool use. defer_loading is part of tool-search; allowed_callers restricts what context can invoke the tool (direct vs from inside code execution).
4. Response shape
{
"id": "msg_013Zva2CMHLNnXjNJJKqJ2EF",
"type": "message",
"role": "assistant",
"model": "claude-opus-4-7",
"content": [ /* ContentBlock[] */ ],
"stop_reason": "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | "pause_turn" | "refusal",
"stop_sequence": null,
"stop_details": {
"type": "refusal",
"category": "cyber" | "bio",
"explanation": "..."
},
"usage": {
"input_tokens": 10,
"output_tokens": 12,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 0,
"cache_creation": {
"ephemeral_5m_input_tokens": 0,
"ephemeral_1h_input_tokens": 0
},
"server_tool_use": {
"web_search_requests": 0,
"web_fetch_requests": 0
},
"inference_geo": "us",
"service_tier": "standard" | "priority" | "batch"
},
"container": { "id": "...", "expires_at": "..." }
}4.1 Stop reasons
| Value | Meaning |
|---|---|
end_turn | Natural stopping point (Claude decided it was done). |
max_tokens | Output hit max_tokens ceiling. |
stop_sequence | Custom stop sequence generated. |
tool_use | Model invoked one or more tools — caller must execute and reply with tool_result. |
pause_turn | Long-running turn paused (server-tool execution still running). Send back the same messages array to resume. |
refusal | Policy violation prevented response. stop_details.category is cyber or bio for the two hard-coded categories. |
4.2 Response content blocks (more shapes than request side)
{type: "text", text, citations?: Citation[]}— citations populated when grounding is enabled{type: "tool_use", id, name, input, caller?}— client-tool invocation{type: "server_tool_use", id, name, input, caller?}— Anthropic-executed server tool (web_search, web_fetch, code_execution, bash, text_editor, tool_search_tool_*){type: "web_search_tool_result", tool_use_id, content}— search results inline{type: "web_fetch_tool_result", tool_use_id, content}{type: "code_execution_tool_result", tool_use_id, content}(alsobash_*,text_editor_*){type: "thinking", thinking, signature}— extended thinking{type: "redacted_thinking", data}
4.3 Citation shapes (in text block)
{type: "char_location", cited_text, document_index, document_title, file_id?, start_char_index, end_char_index}— plain text docs (0-indexed, exclusive end){type: "page_location", cited_text, document_index, document_title, start_page_number, end_page_number}— PDFs (1-indexed, exclusive end){type: "content_block_location", cited_text, document_index, document_title, start_block_index, end_block_index}— custom-content docs (0-indexed){type: "web_search_result_location", cited_text, url, encrypted_index, title}— fromweb_search_*{type: "search_result_location", cited_text, search_result_index, source, start_block_index, end_block_index}— fromsearch_resultcontent blocks
See citations-and-grounding for the full mechanics.
5. Streaming (SSE)
Set "stream": true. Server-Sent Events arrive in this sequence:
event: message_start
data: {"type": "message_start", "message": { /* Message with empty content */ }}
event: content_block_start
data: {"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "Hi"}}
event: content_block_delta
data: {"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "!"}}
event: content_block_stop
data: {"type": "content_block_stop", "index": 0}
event: message_delta
data: {"type": "message_delta", "delta": {"stop_reason": "end_turn"}, "usage": {"output_tokens": 12}}
event: message_stop
data: {"type": "message_stop"}
event: ping
data: {"type": "ping"} # keepalive; ignore
Delta types
text_delta(text)input_json_delta(partial_json) — incremental tool input as JSONthinking_delta(thinking) — extended-thinking textsignature_delta(signature) — thinking signaturecitations_delta(citation) — appended to the currenttextblock’scitationsarray
Error event
event: error
data: {"type": "error", "error": {"type": "overloaded_error", "message": "..."}}
Streaming errors arrive mid-stream and the connection closes. Handle defensively.
6. Errors
HTTP status codes
| Status | Type | When |
|---|---|---|
| 200 | success | Normal completion. |
| 400 | invalid_request_error | Schema validation failures, unsupported feature combos, missing required field. |
| 401 | authentication_error | Bad / missing API key. |
| 403 | permission_error | Workspace lacks access to the feature (e.g. web search not enabled in console). |
| 404 | not_found_error | Unknown model ID, batch ID, file ID. |
| 413 | request_too_large | Request body > limit (32 MB on standard endpoints). |
| 429 | rate_limit_error | Hit org / workspace rate limit; backoff per retry-after header. |
| 500 | api_error | Server-side bug; retry with jitter. |
| 529 | overloaded_error | Org has more load than capacity; backoff. This is the one to handle defensively in long-running agents. |
Body shape
{ "error": { "type": "...", "message": "..." } }The Python SDK raises anthropic.APIStatusError subclasses (anthropic.BadRequestError, RateLimitError, APIConnectionError, OverloadedError, etc.). The TS SDK throws Anthropic.APIError subclasses with .status and .error properties.
7. Rate-limit headers
Returned on every response (200 and 429):
anthropic-ratelimit-requests-limit: 4000
anthropic-ratelimit-requests-remaining: 3995
anthropic-ratelimit-requests-reset: 2026-05-25T12:34:56Z
anthropic-ratelimit-tokens-limit: 400000
anthropic-ratelimit-tokens-remaining: 398500
anthropic-ratelimit-tokens-reset: 2026-05-25T12:34:56Z
anthropic-ratelimit-input-tokens-limit: 200000 # newer split limits
anthropic-ratelimit-input-tokens-remaining: 199100
anthropic-ratelimit-output-tokens-limit: 200000
anthropic-ratelimit-output-tokens-remaining: 199400
request-id: 4c2d6f...
retry-after: 12 # only on 429 / 529
The headers split into requests-per-minute, tokens-per-minute (combined), and the newer split input/output-tokens-per-minute. Limits scale with usage tier per Anthropic’s rate-limit policy — Tier 1 starts low, auto-promoted as you spend.
8. Python SDK
Install:
pip install anthropicBasic call:
import anthropic
client = anthropic.Anthropic() # picks up ANTHROPIC_API_KEY
response = client.messages.create(
model="claude-opus-4-7",
max_tokens=1024,
system="You are a helpful assistant.",
messages=[{"role": "user", "content": "Hello, Claude!"}],
)
print(response.content[0].text)
print(response.usage)Streaming:
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=2048,
messages=[{"role": "user", "content": "Write a haiku about caching."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message()
print("\n\nUsage:", final.usage)Async:
import asyncio
import anthropic
async def main():
client = anthropic.AsyncAnthropic()
async with client.messages.stream(
model="claude-haiku-4-5",
max_tokens=512,
messages=[{"role": "user", "content": "Quick fact about prime numbers."}],
) as stream:
async for text in stream.text_stream:
print(text, end="", flush=True)
asyncio.run(main())Tools with retries / idempotency:
client = anthropic.Anthropic(
max_retries=3, # default 2
timeout=120.0, # default 600s; per-request override available
default_headers={"anthropic-beta": "extended-cache-ttl-2025-04-11"},
)
response = client.with_options(timeout=300.0).messages.create(...)The SDK auto-retries on 408, 409, 429, and 5xx with exponential backoff.
Token-counting endpoint
count = client.messages.count_tokens(
model="claude-opus-4-7",
system="You are concise.",
messages=[{"role": "user", "content": "..."}],
)
print(count.input_tokens, count.cache_read_input_tokens, count.cache_creation_input_tokens)9. TypeScript SDK
Install:
npm install @anthropic-ai/sdkBasic call:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // ANTHROPIC_API_KEY
const response = await client.messages.create({
model: "claude-opus-4-7",
max_tokens: 1024,
system: "You are a helpful assistant.",
messages: [{ role: "user", content: "Hello, Claude!" }],
});
console.log((response.content[0] as Anthropic.TextBlock).text);Streaming:
const stream = await client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 2048,
messages: [{ role: "user", content: "Stream me a poem." }],
});
for await (const event of stream) {
if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
process.stdout.write(event.delta.text);
}
}
const final = await stream.finalMessage();
console.log("\nUsage:", final.usage);The TS SDK exposes:
client.messages.create({...})— non-streamingclient.messages.stream({...})— typed event iteratorclient.messages.countTokens({...})client.messages.batches.create({...})/.retrieve({id})/.results({id})/.cancel({id})client.files.upload({...})/.retrieve({id})/.download({id})/.list()/.delete({id})client.models.list()/.retrieve({id})client.beta.*— beta namespace for features requiring beta headers
10. Other SDKs
| Language | Package | GitHub | Notes |
|---|---|---|---|
| Python | anthropic | anthropic-sdk-python | First-party, complete |
| TypeScript / Node | @anthropic-ai/sdk | anthropic-sdk-typescript | First-party, complete; works in Cloudflare Workers, Vercel Edge, Deno, Bun |
| Go | github.com/anthropics/anthropic-sdk-go | anthropic-sdk-go | First-party |
| Java | com.anthropic:anthropic-java | anthropic-sdk-java | First-party; OkHttp transport |
| C# / .NET | Anthropic.SDK | anthropic-sdk-dotnet | First-party |
| PHP | anthropic/sdk | anthropic-sdk-php | First-party |
| Ruby | anthropic | anthropic-sdk-ruby | First-party |
All first-party SDKs share the same OpenAPI-generated codebase, so parameter names and shapes match (with language-idiomatic case conversion: snake_case Python/Ruby, camelCase TS/Go/Java/C#, snake_case PHP per its array convention).
Language-specific quirks
- Python: pass
cache_control={"type": "ephemeral"}as a dict; the SDK accepts both dict and Pydantic model forms. - TypeScript: response types are unions — narrow with discriminator checks (
if (block.type === "text")). - Go: heavy use of
param.Field[T]wrappers to distinguish “unset” from “zero value”; usesanthropic.NewUserMessage(anthropic.NewTextBlock("..."))helpers. - Java: builder pattern (
MessageCreateParams.builder().model(Model.CLAUDE_OPUS_4_7).maxTokens(1024L).addUserMessage("...").build()). - C#: object-initializer syntax (
new MessageCreateParams { Model = Model.ClaudeOpus4_7, MaxTokens = 1024, ... }).
11. Cloud-provider SDKs
- AWS Bedrock: use the official
boto3Bedrock client or LangChain’sChatBedrockConverse. Model IDs areanthropic.claude-*-v1:0form. - Vertex AI: use
google-cloud-aiplatformPython SDK or REST directly. Model IDs areclaude-*@DATEform. - Microsoft Foundry: use the Azure AI Foundry SDK; same Anthropic-style payload, different auth.
Anthropic also publishes a thin anthropic[bedrock] and anthropic[vertex] extras for the official Python SDK that wrap the cloud SDKs and let you use the same client.messages.create(...) calls:
from anthropic import AnthropicBedrock, AnthropicVertex
bedrock_client = AnthropicBedrock(aws_region="us-west-2")
vertex_client = AnthropicVertex(region="us-central1", project_id="my-project")12. Idempotency and retries
The API does not support explicit idempotency keys. To get idempotent behavior:
- Build at the application layer: hash the request, store result, dedupe on retry.
- Rely on the SDK’s built-in retry (handles 5xx + 429 + 408 + 409 transparently with exponential backoff and jitter).
- For batches: a batch is naturally idempotent — submit once, poll by ID.
For streaming, partial-message replay is not supported — if the connection drops mid-stream, you re-send the original request and get a fresh full generation.
13. Request-size and message limits
Per platform.claude.com/docs/en/api/overview:
- Body size: 32 MB on standard endpoints. Bedrock and Vertex are lower (often 4-8 MB).
- Messages: no documented hard limit on number of messages — bounded by context window in tokens.
max_tokens: bounded by model’s max output (see claude-models-and-capabilities); Batches API can extend to 300k for Opus 4.7 / 4.6 / Sonnet 4.6 with theoutput-300k-2026-03-24beta header.- Tool count: no explicit cap, but the tool-definition tokens count toward input. Practical cap is in the hundreds before context-window pressure dominates.
14. Further reading
- Messages API reference — request/response schemas
- API overview — auth, versioning, size limits
- Rate limits — tiers, headers, scaling
- Streaming guide — SSE event semantics
- Errors and retries
- Python SDK README
- TypeScript SDK README
- Client SDKs overview
- Beta headers