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

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 inference
  • POST /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 / retrieve
  • POST /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-key is case-insensitive in the standard; SDKs use X-Api-Key capitalization.
  • anthropic-version is required. The current frozen value is 2023-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-capabilities
  • messages (array of MessageParam) — at least one user message
  • max_tokens (integer) — max tokens to generate (1 to model-specific max output)

3.2 Common optional

ParamTypeDefaultNotes
systemstring | TextBlockParam[]System prompt. As an array, each block can carry its own cache_control.
temperaturenumber1.00.0 to 1.0. Removed on Opus 4.7 — sampling parameters dropped in favor of effort levels (per Opus 4.7 migration guide).
top_pnumberNucleus sampling. Same Opus 4.7 caveat.
top_knumberSame Opus 4.7 caveat.
stop_sequencesstring[]Custom text sequences to stop generation.
streambooleanfalseEnable SSE.
metadata{user_id: string}For abuse / rate-limit hashing. Do not put PII here.
toolsToolUnion[]Tool definitions; see tool-use-and-function-calling.
tool_choiceToolChoice{type: "auto"}{type: "any" | "auto" | "tool" | "none", name?, disable_parallel_tool_use?}
thinkingThinkingConfigParam{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_geostringPin inference to a region (Vertex / Bedrock regional endpoints).
containerstringReuse 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

ValueMeaning
end_turnNatural stopping point (Claude decided it was done).
max_tokensOutput hit max_tokens ceiling.
stop_sequenceCustom stop sequence generated.
tool_useModel invoked one or more tools — caller must execute and reply with tool_result.
pause_turnLong-running turn paused (server-tool execution still running). Send back the same messages array to resume.
refusalPolicy 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} (also bash_*, 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} — from web_search_*
  • {type: "search_result_location", cited_text, search_result_index, source, start_block_index, end_block_index} — from search_result content 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 JSON
  • thinking_delta (thinking) — extended-thinking text
  • signature_delta (signature) — thinking signature
  • citations_delta (citation) — appended to the current text block’s citations array

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

StatusTypeWhen
200successNormal completion.
400invalid_request_errorSchema validation failures, unsupported feature combos, missing required field.
401authentication_errorBad / missing API key.
403permission_errorWorkspace lacks access to the feature (e.g. web search not enabled in console).
404not_found_errorUnknown model ID, batch ID, file ID.
413request_too_largeRequest body > limit (32 MB on standard endpoints).
429rate_limit_errorHit org / workspace rate limit; backoff per retry-after header.
500api_errorServer-side bug; retry with jitter.
529overloaded_errorOrg 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 anthropic

Basic 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/sdk

Basic 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-streaming
  • client.messages.stream({...}) — typed event iterator
  • client.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

LanguagePackageGitHubNotes
Pythonanthropicanthropic-sdk-pythonFirst-party, complete
TypeScript / Node@anthropic-ai/sdkanthropic-sdk-typescriptFirst-party, complete; works in Cloudflare Workers, Vercel Edge, Deno, Bun
Gogithub.com/anthropics/anthropic-sdk-goanthropic-sdk-goFirst-party
Javacom.anthropic:anthropic-javaanthropic-sdk-javaFirst-party; OkHttp transport
C# / .NETAnthropic.SDKanthropic-sdk-dotnetFirst-party
PHPanthropic/sdkanthropic-sdk-phpFirst-party
Rubyanthropicanthropic-sdk-rubyFirst-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”; uses anthropic.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 boto3 Bedrock client or LangChain’s ChatBedrockConverse. Model IDs are anthropic.claude-*-v1:0 form.
  • Vertex AI: use google-cloud-aiplatform Python SDK or REST directly. Model IDs are claude-*@DATE form.
  • 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:

  1. Build at the application layer: hash the request, store result, dedupe on retry.
  2. Rely on the SDK’s built-in retry (handles 5xx + 429 + 408 + 409 transparently with exponential backoff and jitter).
  3. 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 the output-300k-2026-03-24 beta 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