claude-api
Calling the Claude API
Use the official Anthropic SDK for the language you are in (anthropic for Python, @anthropic-ai/sdk for TypeScript), or raw HTTP only when there is no SDK or the request is explicitly a cURL/REST one. Never mix the two, and never swap in an OpenAI-compatible shim. Read the API key from a 3B credential or connector rather than hardcoding it.
Pick the simplest surface that works
- Single call — classification, summarization, extraction, Q&A. One request, one response.
- Workflow (call + tool use) — multi-step logic you orchestrate in code. You control the loop; Claude calls the tools you define.
- Agent — Claude decides its own trajectory using your tools. Only reach for this when the task is genuinely open-ended, the value justifies the cost, and errors are recoverable.
Everything goes through POST /v1/messages. Tool use and structured outputs are features of that one endpoint, not separate APIs.
Choosing a model
Use the current Claude models — Fable for the hardest knowledge work and coding, Opus for demanding general work, Sonnet for a balance of speed and intelligence, and Haiku for cheap, fast work. Use the exact model ID string (e.g. claude-fable-5, claude-opus-5, claude-sonnet-5, claude-haiku-4-5) and do not append a date suffix. If you need the live context window or capabilities of a model, query the Models API (client.models.list() / client.models.retrieve(id)) rather than relying on memory. Don’t silently downgrade a model to save cost — that’s the caller’s decision.
Prompt caching (do this by default)
Caching is a prefix match: any byte change anywhere in the prefix invalidates everything after it. Render order is tools → system → messages. Put stable content first (frozen system prompt, deterministic tool list) and volatile content (timestamps, per-request IDs, the varying question) last, after your final cache_control breakpoint. The minimum cacheable prefix varies by model — 512 tokens for Opus 5 and Fable 5, 1024 for Sonnet 5, and 4096 for Haiku 4.5 — and differs again on Bedrock, so check the prompt caching docs for the model you picked. Verify it works by checking usage.cache_read_input_tokens across repeated requests — if it stays zero, a silent invalidator (a datetime.now() in the system prompt, unsorted JSON, a varying tool list) is breaking the prefix.