Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build LLM-powered apps with the Anthropic Claude API or SDK across Python, TypeScript, Java, Go, Ruby, C#, and PHP.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
typescript/claude-api/README.md
1# Claude API — TypeScript23## Installation45```bash6npm install @anthropic-ai/sdk7```89## Client Initialization1011```typescript12import Anthropic from "@anthropic-ai/sdk";1314// Default (uses ANTHROPIC_API_KEY env var)15const client = new Anthropic();1617// Explicit API key18const client = new Anthropic({ apiKey: "your-api-key" });19```2021---2223## Basic Message Request2425```typescript26const response = await client.messages.create({27model: "claude-opus-4-7",28max_tokens: 16000,29messages: [{ role: "user", content: "What is the capital of France?" }],30});31// response.content is ContentBlock[] — a discriminated union. Narrow by .type32// before accessing .text (TypeScript will error on content[0].text without this).33for (const block of response.content) {34if (block.type === "text") {35console.log(block.text);36}37}38```3940---4142## System Prompts4344```typescript45const response = await client.messages.create({46model: "claude-opus-4-7",47max_tokens: 16000,48system:49"You are a helpful coding assistant. Always provide examples in Python.",50messages: [{ role: "user", content: "How do I read a JSON file?" }],51});52```5354---5556## Vision (Images)5758### URL5960```typescript61const response = await client.messages.create({62model: "claude-opus-4-7",63max_tokens: 16000,64messages: [65{66role: "user",67content: [68{69type: "image",70source: { type: "url", url: "https://example.com/image.png" },71},72{ type: "text", text: "Describe this image" },73],74},75],76});77```7879### Base648081```typescript82import fs from "fs";8384const imageData = fs.readFileSync("image.png").toString("base64");8586const response = await client.messages.create({87model: "claude-opus-4-7",88max_tokens: 16000,89messages: [90{91role: "user",92content: [93{94type: "image",95source: { type: "base64", media_type: "image/png", data: imageData },96},97{ type: "text", text: "What's in this image?" },98],99},100],101});102```103104---105106## Prompt Caching107108**Caching is a prefix match** — any byte change anywhere in the prefix invalidates everything after it. For placement patterns, architectural guidance (frozen system prompt, deterministic tool order, where to put volatile content), and the silent-invalidator audit checklist, read `shared/prompt-caching.md`.109110### Automatic Caching (Recommended)111112Use top-level `cache_control` to automatically cache the last cacheable block in the request:113114```typescript115const response = await client.messages.create({116model: "claude-opus-4-7",117max_tokens: 16000,118cache_control: { type: "ephemeral" }, // auto-caches the last cacheable block119system: "You are an expert on this large document...",120messages: [{ role: "user", content: "Summarize the key points" }],121});122```123124### Manual Cache Control125126For fine-grained control, add `cache_control` to specific content blocks:127128```typescript129const response = await client.messages.create({130model: "claude-opus-4-7",131max_tokens: 16000,132system: [133{134type: "text",135text: "You are an expert on this large document...",136cache_control: { type: "ephemeral" }, // default TTL is 5 minutes137},138],139messages: [{ role: "user", content: "Summarize the key points" }],140});141142// With explicit TTL (time-to-live)143const response2 = await client.messages.create({144model: "claude-opus-4-7",145max_tokens: 16000,146system: [147{148type: "text",149text: "You are an expert on this large document...",150cache_control: { type: "ephemeral", ttl: "1h" }, // 1 hour TTL151},152],153messages: [{ role: "user", content: "Summarize the key points" }],154});155```156157### Verifying Cache Hits158159```typescript160console.log(response.usage.cache_creation_input_tokens); // tokens written to cache (~1.25x cost)161console.log(response.usage.cache_read_input_tokens); // tokens served from cache (~0.1x cost)162console.log(response.usage.input_tokens); // uncached tokens (full cost)163```164165If `cache_read_input_tokens` is zero across repeated identical-prefix requests, a silent invalidator is at work — `Date.now()` or a UUID in the system prompt, non-deterministic key ordering, or a varying tool set. See `shared/prompt-caching.md` for the full audit table.166167---168169## Extended Thinking170171> **Opus 4.7, Opus 4.6, and Sonnet 4.6:** Use adaptive thinking. `budget_tokens` is removed on Opus 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6.172> **Older models:** Use `thinking: {type: "enabled", budget_tokens: N}` (must be < `max_tokens`, min 1024).173174```typescript175// Opus 4.7 / 4.6: adaptive thinking (recommended)176const response = await client.messages.create({177model: "claude-opus-4-7",178max_tokens: 16000,179thinking: { type: "adaptive" },180output_config: { effort: "high" }, // low | medium | high | max181messages: [182{ role: "user", content: "Solve this math problem step by step..." },183],184});185186for (const block of response.content) {187if (block.type === "thinking") {188console.log("Thinking:", block.thinking);189} else if (block.type === "text") {190console.log("Response:", block.text);191}192}193```194195---196197## Error Handling198199Use the SDK's typed exception classes — never check error messages with string matching:200201```typescript202import Anthropic from "@anthropic-ai/sdk";203204try {205const response = await client.messages.create({...});206} catch (error) {207if (error instanceof Anthropic.BadRequestError) {208console.error("Bad request:", error.message);209} else if (error instanceof Anthropic.AuthenticationError) {210console.error("Invalid API key");211} else if (error instanceof Anthropic.RateLimitError) {212console.error("Rate limited - retry later");213} else if (error instanceof Anthropic.APIError) {214console.error(`API error ${error.status}:`, error.message);215}216}217```218219All classes extend `Anthropic.APIError` with a typed `status` field. Check from most specific to least specific. See [shared/error-codes.md](../../shared/error-codes.md) for the full error code reference.220221---222223## Multi-Turn Conversations224225The API is stateless — send the full conversation history each time. Use `Anthropic.MessageParam[]` to type the messages array:226227```typescript228const messages: Anthropic.MessageParam[] = [229{ role: "user", content: "My name is Alice." },230{ role: "assistant", content: "Hello Alice! Nice to meet you." },231{ role: "user", content: "What's my name?" },232];233234const response = await client.messages.create({235model: "claude-opus-4-7",236max_tokens: 16000,237messages: messages,238});239```240241**Rules:**242243- Consecutive same-role messages are allowed — the API combines them into a single turn244- First message must be `user`245- Use SDK types (`Anthropic.MessageParam`, `Anthropic.Message`, `Anthropic.Tool`, etc.) for all API data structures — don't redefine equivalent interfaces246247---248249### Compaction (long conversations)250251> **Beta, Opus 4.7, Opus 4.6, and Sonnet 4.6.** When conversations approach the 200K context window, compaction automatically summarizes earlier context server-side. The API returns a `compaction` block; you must pass it back on subsequent requests — append `response.content`, not just the text.252253```typescript254import Anthropic from "@anthropic-ai/sdk";255256const client = new Anthropic();257const messages: Anthropic.Beta.BetaMessageParam[] = [];258259async function chat(userMessage: string): Promise<string> {260messages.push({ role: "user", content: userMessage });261262const response = await client.beta.messages.create({263betas: ["compact-2026-01-12"],264model: "claude-opus-4-7",265max_tokens: 16000,266messages,267context_management: {268edits: [{ type: "compact_20260112" }],269},270});271272// Append full content — compaction blocks must be preserved273messages.push({ role: "assistant", content: response.content });274275const textBlock = response.content.find(276(b): b is Anthropic.Beta.BetaTextBlock => b.type === "text",277);278return textBlock?.text ?? "";279}280281// Compaction triggers automatically when context grows large282console.log(await chat("Help me build a Python web scraper"));283console.log(await chat("Add support for JavaScript-rendered pages"));284console.log(await chat("Now add rate limiting and error handling"));285```286287---288289## Stop Reasons290291The `stop_reason` field in the response indicates why the model stopped generating:292293| Value | Meaning |294| --------------- | --------------------------------------------------------------- |295| `end_turn` | Claude finished its response naturally |296| `max_tokens` | Hit the `max_tokens` limit — increase it or use streaming |297| `stop_sequence` | Hit a custom stop sequence |298| `tool_use` | Claude wants to call a tool — execute it and continue |299| `pause_turn` | Model paused and can be resumed (agentic flows) |300| `refusal` | Claude refused for safety reasons — output may not match schema |301302---303304## Cost Optimization Strategies305306### 1. Use Prompt Caching for Repeated Context307308```typescript309// Automatic caching (simplest — caches the last cacheable block)310const response = await client.messages.create({311model: "claude-opus-4-7",312max_tokens: 16000,313cache_control: { type: "ephemeral" },314system: largeDocumentText, // e.g., 50KB of context315messages: [{ role: "user", content: "Summarize the key points" }],316});317318// First request: full cost319// Subsequent requests: ~90% cheaper for cached portion320```321322### 2. Use Token Counting Before Requests323324```typescript325const countResponse = await client.messages.countTokens({326model: "claude-opus-4-7",327messages: messages,328system: system,329});330331const estimatedInputCost = countResponse.input_tokens * 0.000005; // $5/1M tokens332console.log(`Estimated input cost: $${estimatedInputCost.toFixed(4)}`);333```334