All skills
anthropics avatar

/claude-api

@8a1541c official
by Anthropicanthropics/skills179k stars
21,201

Reference for the Claude API / Anthropic SDK — model ids, pricing, params, streaming, tool use, MCP, agents, caching, token counting, model migration. TRIGGER — read BEFORE opening the target file; don't skip because it "looks like a one-liner" — whenever: the prompt names Claude/Anthropic in any form (Claude, Anthropic, Fable, Opus, Sonnet, Haiku, `anthropic`, `@anthropic-ai`, `claude-*`, `us.anthropic.*`, `[1m]`); the user asks about an LLM (pricing/model choice/limits/caching) — never answer from memory; OR the task is LLM-shaped with provider unstated (agent/MCP/tool-definition/multi-agent/RAG/LLM-judge/computer-use; generate/summarize/extract/classify/rewrite/converse over NL; debugging refusals/cutoffs/streaming/tool-calls/tokens). SKIP only when another provider is being worked on (overrides all triggers): OpenAI/GPT/Gemini/Llama/Mistral/Cohere/Ollama named in the query; OR `grep -rE 'openai|langchain_openai|google.generativeai|genai|mistralai|cohere|ollama'` over the project hits (run this grep FIRST if no provider named — don't Read the file).

Use this Skill: https://skilld.dev/gh/anthropics/skills/claude-api

This session only. Nothing lands on disk.

typescriptclaude-apiREADME.md

≈3.9k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Claude API - TypeScript

Feature Namespace Key types / call
User profiles beta client.beta.userProfiles.create(...) / .retrieve(id) / .list(). Pass the returned profile id on client.beta.messages.create. Requires a beta header - check the SDK's beta-headers reference for the current flag.

Installation

npm install @anthropic-ai/sdk

Reading local files (ESM): __dirname and __filename are undefined in ES modules - using either throws ReferenceError: __dirname is not defined at runtime. For cwd-relative reads, pass the bare relative path (fs.readFileSync("./sample.png")). For script-relative paths, derive the directory from import.meta.url: const here = path.dirname(fileURLToPath(import.meta.url)). Never write path.join(__dirname, ...) in an ESM .ts file.

Client Initialization

import Anthropic from "@anthropic-ai/sdk";

// Default - resolves credentials from the environment:
// ANTHROPIC_API_KEY, or ANTHROPIC_AUTH_TOKEN, or an `ant auth login` profile.
// Prefer this for local dev; don't hardcode a key.
const client = new Anthropic();

// Explicit API key (only when you must inject a specific key)
const client = new Anthropic({ apiKey: "your-api-key" });

Basic Message Request

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  messages: [{ role: "user", content: "What is the capital of France?" }],
});
// response.content is ContentBlock[] - a discriminated union. Narrow by .type
// before accessing .text (TypeScript will error on content[0].text without this).
for (const block of response.content) {
  if (block.type === "text") {
    console.log(block.text);
  }
}

System Prompts

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  system:
    "You are a helpful coding assistant. Always provide examples in Python.",
  messages: [{ role: "user", content: "How do I read a JSON file?" }],
});

Mid-conversation system messages (model-gated)

For operator instructions that arrive mid-conversation (mode switches, injected state), append {role: "system", ...} to messages instead of editing top-level system - this preserves the cached prefix and carries operator authority. Must follow a user message (or an assistant message ending in server-tool use), and must be either the last entry in messages or be followed by an assistant turn; cannot be messages[0]. Unsupported models return a 400 (role 'system' is not supported on this model). See shared/prompt-caching.md for when to use this vs. top-level system.

// No beta header needed - use regular client.messages.create.
const response = await client.messages.create({
  model: MODEL_ID, // must support mid-conversation system messages
  max_tokens: 16000,
  system: [
    { type: "text", text: STABLE_SYSTEM, cache_control: { type: "ephemeral" } },
  ],
  messages: [
    ...history,
    { role: "user", content: userMessage },
    { role: "system", content: "Terse mode enabled - keep responses under 40 words." },
  ],
});

Vision (Images)

URL

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  messages: [
    {
      role: "user",
      content: [
        {
          type: "image",
          source: { type: "url", url: "https://example.com/image.png" },
        },
        { type: "text", text: "Describe this image" },
      ],
    },
  ],
});

Base64

import fs from "fs";

const imageData = fs.readFileSync("image.png").toString("base64");

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  messages: [
    {
      role: "user",
      content: [
        {
          type: "image",
          source: { type: "base64", media_type: "image/png", data: imageData },
        },
        { type: "text", text: "What's in this image?" },
      ],
    },
  ],
});

Prompt Caching

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.

Automatic Caching (Recommended)

Use top-level cache_control to automatically cache the last cacheable block in the request:

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  cache_control: { type: "ephemeral" }, // auto-caches the last cacheable block
  system: "You are an expert on this large document...",
  messages: [{ role: "user", content: "Summarize the key points" }],
});

Manual Cache Control

For fine-grained control, add cache_control to specific content blocks:

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  system: [
    {
      type: "text",
      text: "You are an expert on this large document...",
      cache_control: { type: "ephemeral" }, // default TTL is 5 minutes
    },
  ],
  messages: [{ role: "user", content: "Summarize the key points" }],
});

// With explicit TTL (time-to-live)
const response2 = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  system: [
    {
      type: "text",
      text: "You are an expert on this large document...",
      cache_control: { type: "ephemeral", ttl: "1h" }, // 1 hour TTL
    },
  ],
  messages: [{ role: "user", content: "Summarize the key points" }],
});

Verifying Cache Hits

console.log(response.usage.cache_creation_input_tokens); // tokens written to cache (~1.25x cost)
console.log(response.usage.cache_read_input_tokens);     // tokens served from cache (~0.1x cost)
console.log(response.usage.input_tokens);                // uncached tokens (full cost)

If 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.


Extended Thinking

Fable 5, Claude Opus 5.5, Claude Opus 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6: Use adaptive thinking. budget_tokens is removed on Fable 5, Claude Opus 5.5, Claude Opus 5, Opus 4.8, and 4.7 (400 if sent); deprecated on Opus 4.6 and Sonnet 4.6. Claude Opus 5.5: thinking is always on - omit thinking (or send { type: "adaptive" }, which is equivalent); { type: "disabled" } returns a 400 at every effort, as does a thinking budget. Control depth with output_config.effort instead - the default is medium on this model, where Claude Opus 5 defaults to high. Claude Opus 5: thinking is on by default - omitting thinking runs adaptive ({ type: "adaptive" } is equivalent), unlike Opus 4.8/4.7 where omitting it meant no thinking. { type: "disabled" } is accepted only at effort high or lower; pairing it with xhigh/max returns a 400. Older models: Use thinking: {type: "enabled", budget_tokens: N} (must be < max_tokens, min 1024).

// Fable 5 / Claude Opus 5.5 / Claude Opus 5 / Opus 4.8 / 4.7 / 4.6: adaptive thinking (recommended)
const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  thinking: { type: "adaptive", display: "summarized" }, // display opt-in: default is omitted (empty thinking text) on Fable 5/5.1, Mythos 5/5.1, Claude Opus 5.5, Claude Opus 5, Opus 4.8/4.7, Claude Sonnet 5.5, and Claude Sonnet 5
  output_config: { effort: "high" }, // low | medium | high | xhigh | max
  messages: [
    { role: "user", content: "Solve this math problem step by step..." },
  ],
});

for (const block of response.content) {
  if (block.type === "thinking") {
    console.log("Thinking:", block.thinking);
  } else if (block.type === "text") {
    console.log("Response:", block.text);
  }
}

Error Handling

Use the SDK's typed exception classes - never check error messages with string matching:

import Anthropic from "@anthropic-ai/sdk";

try {
  const response = await client.messages.create({...});
} catch (error) {
  if (error instanceof Anthropic.BadRequestError) {
    console.error("Bad request:", error.message);
  } else if (error instanceof Anthropic.AuthenticationError) {
    console.error("Invalid API key");
  } else if (error instanceof Anthropic.RateLimitError) {
    console.error("Rate limited - retry later");
  } else if (error instanceof Anthropic.APIError) {
    console.error(`API error ${error.status}:`, error.message);
  }
}

All classes extend Anthropic.APIError with a typed status field. Check from most specific to least specific. See shared/error-codes.md for the full error code reference.


Multi-Turn Conversations

The API is stateless - send the full conversation history each time. Use Anthropic.MessageParam[] to type the messages array:

const messages: Anthropic.MessageParam[] = [
  { role: "user", content: "My name is Alice." },
  { role: "assistant", content: "Hello Alice! Nice to meet you." },
  { role: "user", content: "What's my name?" },
];

const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  messages: messages,
});

Rules:

  • Consecutive same-role messages are allowed - the API combines them into a single turn
  • First message must be user
  • Use SDK types (Anthropic.MessageParam, Anthropic.Message, Anthropic.Tool, etc.) for all API data structures - don't redefine equivalent interfaces

Compaction (long conversations)

Beta, Fable 5, Claude Opus 5.5, Claude Opus 5, Opus 4.8, 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.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();
const messages: Anthropic.Beta.BetaMessageParam[] = [];

async function chat(userMessage: string): Promise<string> {
  messages.push({ role: "user", content: userMessage });

  const response = await client.beta.messages.create({
    betas: ["compact-2026-01-12"],
    model: "claude-opus-5-5",
    max_tokens: 16000,
    messages,
    context_management: {
      edits: [{ type: "compact_20260112" }],
    },
  });

  // Append full content - compaction blocks must be preserved
  messages.push({ role: "assistant", content: response.content });

  const textBlock = response.content.find(
    (b): b is Anthropic.Beta.BetaTextBlock => b.type === "text",
  );
  return textBlock?.text ?? "";
}

// Compaction triggers automatically when context grows large
console.log(await chat("Help me build a Python web scraper"));
console.log(await chat("Add support for JavaScript-rendered pages"));
console.log(await chat("Now add rate limiting and error handling"));

Stop Reasons

The stop_reason field in the response indicates why the model stopped generating:

Value Meaning
end_turn Claude finished its response naturally
max_tokens Hit the max_tokens limit - increase it or use streaming
stop_sequence Hit a custom stop sequence
tool_use Claude wants to call a tool - execute it and continue
pause_turn Model paused and can be resumed (agentic flows)
refusal Claude refused for safety reasons - check stop_details

Structured Stop Details

When stop_reason is "refusal", the response includes a stop_details object with structured information about the refusal:

if (response.stop_reason === "refusal" && response.stop_details) {
  console.log(`Category: ${response.stop_details.category}`); // e.g. "cyber", "bio", "reasoning_extraction", "frontier_llm", or null - see docs for the full set
  console.log(`Explanation: ${response.stop_details.explanation}`);
}

Refusal Fallbacks (Claude Fable 5.1) - opt in by default

Fallbacks are opt-in: without them a refused request simply stops. Include the server-side fallbacks parameter in claude-fable-5-1 code by default - on a policy decline the API re-runs the same request on the fallback model inside the same call. A mid-stream decline is billed at normal rates, and the rescue bills at the fallback model's own rates, with cache repricing applied automatically; for a decline before any output, see How refusals are billed.

const response = await client.beta.messages.create({
  model: "claude-fable-5-1",
  max_tokens: 16000,
  betas: ["server-side-fallback-2026-06-01"],
  fallbacks: [{ model: "claude-opus-4-8" }],
  messages: [{ role: "user", content: "..." }],
});

// Switch points: one fallback block per model that ran and declined this turn
for (const block of response.content) {
  if (block.type === "fallback") {
    console.log(`${block.from.model} declined; ${block.to.model} continued`);
  }
}

// Served-by signal - covers sticky turns, which carry no fallback block.
// Pair with stop_reason: the fallback model can itself refuse.
const fallbackRan = (response.usage.iterations ?? []).some(
  (entry) => entry.type === "fallback_message",
);
if (fallbackRan && response.stop_reason !== "refusal") {
  console.log(`Served by ${response.model}`);
}

A stop_reason: "refusal" on the final response means the whole chain refused. The header must be exactly server-side-fallback-2026-06-01 for this array form; the newer fallbacks: "default" scalar form uses server-side-fallback-2026-07-01 instead (see shared/model-migration.md -> Migrating to Claude Opus 5 -> New API features), and pairing either header with the other form returns a 400. The parameter is rejected on the Batches API and unavailable on Amazon Bedrock, Vertex AI, and Microsoft Foundry - register the client-side betaRefusalFallbackMiddleware on the client there instead. Full semantics (sticky routing, billing, streaming, echoing fallback turns back): shared/model-migration.md -> Migrating to Claude Fable 5.1 -> refusal stop reason.


Cost Optimization Strategies

1. Use Prompt Caching for Repeated Context

// Automatic caching (simplest - caches the last cacheable block)
const response = await client.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 16000,
  cache_control: { type: "ephemeral" },
  system: largeDocumentText, // e.g., 50KB of context
  messages: [{ role: "user", content: "Summarize the key points" }],
});

// First request: full cost
// Subsequent requests: ~90% cheaper for cached portion

2. Use Token Counting Before Requests

const countResponse = await client.messages.countTokens({
  model: "claude-opus-5-5",
  messages: messages,
  system: system,
});

const estimatedInputCost = countResponse.input_tokens * 0.000004; // $4/1M tokens
console.log(`Estimated input cost: $${estimatedInputCost.toFixed(4)}`);

Source: SKILL.md on GitHub

1 warning2d5 checks · Risk SAFE
  • Gen Agent Trust Hub2d

    This skill is a developer reference for the Claude API and Anthropic SDKs. It includes some security considerations related to building agents with powerful capabilities like shell command execution and web fetching. While these present a potential surface for indirect prompt injection, the skill provides extensive security guidance, emphasizing sandboxing and input validation as mitigation strategies. All external resources and packages originate from trusted official sources.

  • Socket2d

    No alerts

  • Snyk2d

    Risk: LOW · No issues

  • Runlayer7mo

    12/26 files flagged

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at 8a1541c. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 3 days ago

README badge

README badge for anthropics/skills/claude-api

Reference for the Claude API and official Anthropic SDKs — model IDs, pricing, parameters, streaming, tool use, MCP, managed agents, caching, token counting, and model migration. Read this skill before opening a file that involves Claude, an Anthropic model, agent workflows, or LLM-shaped tasks with no specified provider.

Generated from the current SKILL.md.

Which Claude model should I use by default?
Use Claude Opus 4.8 (model ID: `claude-opus-4-8`) as the default. Also default to adaptive thinking (`thinking: {type: "adaptive"}`) for anything complex, and streaming for requests with long input, output, or high max_tokens.
What should I do if the project uses OpenAI or another non-Anthropic provider?
Stop and ask the user whether they want to switch the file to Claude or want a non-Claude implementation. Do not edit a non-Anthropic file with Anthropic SDK calls.
Should I use the official SDK or raw HTTP?
Use the official Anthropic SDK for your language whenever one exists (Python, TypeScript, Java, Go, Ruby, C#, PHP). Only use raw HTTP (curl, requests, fetch) if the user explicitly asks for it, the project is shell/cURL, or the language has no official SDK.
When should I use Managed Agents versus Claude API with tool use?
Use Managed Agents when you want Anthropic to run the agent loop and host a per-session container for tool execution (file ops, bash, code). Use Claude API with tool use for multi-step workflows where you control the orchestration and host the compute yourself.
Does this skill work with Amazon Bedrock, Google Vertex AI, or Microsoft Foundry?
Managed Agents is not available on those platforms. Use Claude API with tool use instead. Claude Platform on AWS (Anthropic-operated) has full feature parity with the first-party API.

Generated from the current SKILL.md. These answers refresh after source changes.