claude-api skill (anthropics/skills) (part 2)
- SKILL.md (verbatim, continued)
- Server Tools (Quick Reference)
- Document & File Input (Quick Reference)
- Tool Use Patterns (Quick Reference)
- Other API Surfaces (Quick Reference)
- Workload Identity Federation (Quick Reference)
- Reading Guide
- Quick Task Reference
- When to Use WebFetch
- Common Pitfalls
- Other files in this skill
- csharp/claude-api/README.md (verbatim)
- Namespace Reference
- Key types per feature
- Discovering type and member names
- Minimal working skeleton
- Common C# compile errors
- Installation
- Client Initialization
- Basic Message Request
- Thinking
- Context Editing / Compaction (Beta)
- Effort Parameter
- Prompt Caching
- Token Counting
- PDF / Document Input
- Fast Mode (Beta)
- Models API
- Long Output (128k) + Prefill
- Stop Details
- Managed Agents (Beta)
- csharp/claude-api/batches.md (verbatim)
- Message Batches API
- csharp/claude-api/files-api.md (verbatim)
- Files API
- csharp/claude-api/streaming.md (verbatim)
- Streaming
- php/claude-api/batches.md (verbatim)
- Message Batches API
Part 2 of 2 of claude-api skill (anthropics/skills) (skills/claude-api/SKILL.md in anthropics/skills); the SKILL.md text continues verbatim from the previous part.
SKILL.md (verbatim, continued)
When the user wants to set up a Managed Agent from scratch (e.g. "how do I get started", "walk me through creating one", "set up a new agent"): read shared/managed-agents-onboarding.md and run its interview - same flow as the managed-agents-onboard subcommand.
When the user asks "how do I write the client code for X": reach for shared/managed-agents-client-patterns.md - covers lossless stream reconnect, processed_at queued/processed gate, interrupt, tool_confirmation round-trip, the correct idle/terminated break gate, post-idle status race, stream-first ordering, file-mount gotchas, etc. For credentials, lead with vault environment_variable credentials - the first-class mechanism; secrets are substituted at egress and never enter the sandbox (shared/managed-agents-tools.md -> Vaults). Keeping credentials host-side via custom tools is the fallback where vault credentials don't fit (e.g. self-hosted sandboxes).
When the user wants the agent to run on a schedule (cron, "every night", "weekly report"): read shared/managed-agents-scheduled-deployments.md - deployments fire sessions autonomously on a cron cadence, with per-firing run records and lifecycle controls (pause/unpause/archive).
When the agent's work fans out (research across several sources, per-file or per-record work, "look into N things, then summarize") or one loop would fill its context with reading: read shared/managed-agents-multiagent.md and recommend a multiagent session - start with just {"type": "self"} in the roster so the agent can delegate to copies of itself, then move reading-heavy sub-tasks to a cheaper worker agent (e.g. Claude Haiku 4.5) referenced by ID.
Server Tools (Quick Reference)
Server-side tools run on Anthropic's infrastructure - no client-side execution loop. Declare in tools; results arrive as content blocks in the same response. No beta header unless noted. Prefer the latest type variant your model supports. The _20260209 web search / web fetch variants below (dynamic filtering) require Opus 5/4.8/4.7/4.6, Sonnet 5, or Sonnet 4.6; the basic variants for older models are listed after the table.
| Tool | type |
name |
Key optional params | Result block type |
|---|---|---|---|---|
| Web search | web_search_20260209 |
web_search |
max_uses, allowed_domains/blocked_domains, user_location |
web_search_tool_result -> .content is a list of web_search_result |
| Web fetch | web_fetch_20260209 |
web_fetch |
max_uses, allowed_domains/blocked_domains, citations, max_content_tokens |
web_fetch_tool_result -> .content is a web_fetch_result with a document block |
| Code execution | code_execution_20260521 |
code_execution |
none | bash_code_execution_tool_result -> .content.stdout / .stderr / .return_code |
| Tool search (regex) | tool_search_tool_regex_20251119 |
tool_search_tool_regex |
mark other tools defer_loading: true |
tool_search_tool_result |
| Tool search (BM25) | tool_search_tool_bm25_20251119 |
tool_search_tool_bm25 |
mark other tools defer_loading: true |
tool_search_tool_result |
web_search_20260209 / web_fetch_20260209 have built-in dynamic filtering - code execution runs under the hood, so do not separately declare code_execution in tools (a second execution environment confuses the model). For models older than Opus 4.6 / Sonnet 4.6, use the basic variants web_search_20250305 / web_fetch_20250910 instead; on Vertex AI only basic web_search_20250305 is available. code_execution_20260120 (REPL persistence + programmatic tool calling) runs on Opus 4.5+ / Sonnet 4.5+. Go SDK only: code_execution_20260521 lives under client.Beta.Messages.New with Betas: []anthropic.AnthropicBeta{"code-execution-2025-08-25"} (other languages use plain client.messages.create); code_execution_20260120 uses the non-beta client.Messages.New in Go like everywhere else. Web fetch only fetches URLs already present in the conversation. Provider availability varies by tool - see shared/platform-availability.md. See shared/tool-use-concepts.md for pause_turn handling.
Document & File Input (Quick Reference)
PDF (base64, no beta): {"type": "document", "source": {"type": "base64", "media_type": "application/pdf", "data": <b64 string>}} in user content, placed before the text block. Base64 string must have no newlines. Limits: 32 MB request, 600 pages (100 for 200k-context models). Java: ContentBlockParam.ofDocument(DocumentBlockParam... Base64PdfSource.builder().data(...)).
Files API (no beta): upload via client.files.upload(...) -> response id is the file_id. Reference it as {"type": "document", "source": {"type": "file", "file_id": "..."}} for PDF/text, or {"type": "image", ...} for images - the content-block type must match the file's MIME type. To migrate code off files-api-2025-04-14, WebFetch the Files API row in shared/live-sources.md. Availability: shared/platform-availability.md.
Citations (no beta): set citations: {enabled: true} on each document content block (all or none). Response splits into multiple text blocks; cited blocks carry a citations array. Each citation has cited_text, document_index, document_title, and a location by type: char_location (start_char_index/end_char_index) for plain text, page_location (start_page_number/end_page_number, 1-indexed) for PDF, content_block_location for custom content. Incompatible with output_config.format (returns a 400).
Tool Use Patterns (Quick Reference)
Strict tool use (no beta): set strict: true as a top-level field on the tool definition (alongside name/description/input_schema), not on tool_choice. Schema must have additionalProperties: false + required. Guarantees tool_use.input validates exactly. Go: Strict: anthropic.Bool(true) + additionalProperties via InputSchema.ExtraFields; Java: .strict(true) + .putAdditionalProperty("additionalProperties", JsonValue.from(false)).
Parallel tool use (default on): one assistant message may contain multiple tool_use blocks. Execute them concurrently, then return all tool_result blocks in a single user message - splitting them across multiple messages silently trains Claude to stop making parallel calls. For a failed tool, return tool_result with is_error: true - don't drop it.
Tool Runner (SDK beta helper): drives the tool-call loop for you via client.beta.messages.*. Python: @beta_tool decorator + client.beta.messages.tool_runner(...) -> runner.until_done(). TypeScript: betaZodTool({...}) from @anthropic-ai/sdk/helpers/beta/zod + client.beta.messages.toolRunner(...) -> await runner. Go: toolrunner.NewBetaToolFromJSONSchema(...) + client.Beta.Messages.NewToolRunner(...) -> .RunToCompletion(ctx). Java requires .addBeta("structured-outputs-2025-11-13"). Ruby: Anthropic::BaseTool subclass + client.beta.messages.tool_runner(...). PHP: BetaRunnableTool + ->toolRunner(...). C#: raw JSON-schema tools + BetaToolRunner via client.Beta.Messages.ToolRunner(...).
Programmatic tool calling (no beta header): Claude calls your custom tool from inside code execution. Add {"type": "code_execution_20260120", "name": "code_execution"} and set "allowed_callers": ["code_execution_20260120"] on your custom tool. Opus 4.5+ / Sonnet 4.5+ (availability: shared/platform-availability.md). When responding to a pending programmatic call, the user message must contain only tool_result blocks (no text). Not compatible with strict: true, disable_parallel_tool_use, forced tool_choice, or MCP tools.
Other API Surfaces (Quick Reference)
Message Batches (no beta; availability: shared/platform-availability.md): client.messages.batches.create(requests=[{custom_id, params}, ...]) -> poll client.messages.batches.retrieve(id).processing_status until "ended" -> stream client.messages.batches.results(id). Each result has .custom_id + .result.type (succeeded/errored/canceled/expired); on success read .result.message.content. Python wraps requests as Request(custom_id=..., params=MessageCreateParamsNonStreaming(...)). Results arrive in any order - key by custom_id, never by position.
Models API (no beta; availability: shared/platform-availability.md): client.models.list() (auto-paginates) and client.models.retrieve("claude-opus-5"). Each model object has id, display_name, created_at, and - since Mar 2026 - max_input_tokens (the context window), max_tokens (the output cap), and capabilities. There is no context_window field.
Stop details (GA, Opus 4.7+): response.stop_details is populated only when stop_reason == "refusal" (fields: type: "refusal", category - an open set, e.g. "cyber", "bio", "reasoning_extraction", "frontier_llm", or null; see the docs for the full list - and explanation). It is null for every other stop_reason (end_turn, max_tokens, tool_use, pause_turn, ...) - always guard before reading.
Admin API (beta, since 2026-08-26): organization management - members, invites, workspaces and workspace members, API keys, rate limit reports, service accounts, federation issuers/rules, CMEK external keys - under client.beta.organization in all seven SDKs and ant beta:organization in the CLI. Requires an admin credential: an Admin API key (sk-ant-admin..., read from ANTHROPIC_API_KEY) or an org:admin OAuth token (ANTHROPIC_AUTH_TOKEN); regular API keys are rejected. Usage and cost reports and the Claude Enterprise user-management/analytics endpoints are not in the SDKs - raw HTTP only. See shared/admin-api.md.
Client config (no beta): timeout default 10 min; units differ by SDK - Python/Ruby: seconds; TypeScript: milliseconds; Go option.WithRequestTimeout(time.Duration); Java Duration; C# TimeSpan. TS scales the default up to 60 min for large max_tokens on non-streaming requests; Java does so for streaming requests (Java non-streaming scales 30s-10 min). max_retries/maxRetries default 2 (retries 408/409/429/5xx + connection errors). base_url (or ANTHROPIC_BASE_URL env). Per-request override: Python client.with_options(timeout=5.0).messages.create(...); TS client.messages.create({...}, {timeout: 5_000}); Ruby request_options: {timeout: 5}. Timeouts are retried - wall-clock can reach timeout × (max_retries+1).
Workload Identity Federation (Quick Reference)
GA, no beta header. Construct the normal zero-arg client (Anthropic() / new Anthropic() / anthropic.NewClient() / AnthropicOkHttpClient.fromEnv()); the SDK auto-detects WIF when all of ANTHROPIC_FEDERATION_RULE_ID, ANTHROPIC_ORGANIZATION_ID, ANTHROPIC_SERVICE_ACCOUNT_ID, and ANTHROPIC_IDENTITY_TOKEN_FILE (or ANTHROPIC_IDENTITY_TOKEN) are set, exchanges the JWT at /v1/oauth/token, and auto-refreshes. ANTHROPIC_WORKSPACE_ID does not gate activation - required only when the federation rule spans multiple workspaces (else 400 workspace_id_required), optional for single-workspace rules. ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN (even empty) outrank WIF, and a set ANTHROPIC_PROFILE also wins over the federation env vars (a missing named profile is an error, not a fall-through) - unset all three.
Reading Guide
After detecting the language, read the relevant files based on what the user needs. Every {lang}/..., shared/..., and curl/... path cited in this document is relative to this skill's base directory, and none of those files' content is included above - Read each one on demand before relying on what it covers.
All SDK languages use the same multi-file layout - directory {lang}/claude-api/ containing README.md (install, client init, basic request, thinking, caching, stop details, misc), tool-use.md (tool definitions, agentic loop, Anthropic-defined tools, structured outputs), streaming.md, batches.md, files-api.md. Not every language has every file (e.g., Ruby has no batches.md); if a file is absent, that feature's example is not yet documented for that language - fall back to the cURL shape or WebFetch the SDK repo from shared/live-sources.md. cURL -> curl/examples.md.
The Quick Task Reference below uses the {lang}/claude-api/FILE.md path notation for all languages.
Quick Task Reference
Single text classification/summarization/extraction/Q&A:
-> Read only {lang}/claude-api/README.md - always read the README first for any task (installation, quick start, common patterns, error handling)
Chat UI or real-time response display:
-> Read {lang}/claude-api/README.md + {lang}/claude-api/streaming.md
Long-running conversations (may exceed context window):
-> Read {lang}/claude-api/README.md - see Compaction section
Migrating to a newer model (Fable 5.1 / Fable 5 / Opus 5 / Opus 4.8 / Opus 4.7 / Opus 4.6 / Sonnet 5 / Sonnet 4.6), replacing a retired model, or translating budget_tokens / prefill patterns to the current API:
-> Read shared/model-migration.md
Upgrading the Anthropic SDK package itself across a major version (anthropic 0.x -> 1.x: httpx2, awaited async .with_raw_response, removed deprecated parameters / aliases / Text Completions, Python >= 3.10) - or writing new code against a project already on 1.x:
-> Read {lang}/claude-api/sdk-upgrade.md (currently Python only; other SDKs have no bundled major-version guide yet - use that SDK's CHANGELOG via shared/live-sources.md)
Prompting or tuning Fable 5/5.1 (long turns, effort, verbosity, autonomous runs, sub-agents):
-> Read shared/model-migration.md -> Migrating to Claude Fable 5.1 -> Behavioral shifts (prompt-tunable) + Long-running agent recommendations
Prompting or tuning Claude Fable 5.1 (progress updates, parallel tool calls, writing density / formatting, autonomy, test sprawl, whole-file rewrites) or making a harness compatible with preserved thinking's history-editing check (history edits, compaction, per-turn reminders):
-> Read shared/model-migration.md -> Migrating to Claude Fable 5.1 from Claude Fable 5 -> New API features + Behavioral shifts (prompt-tunable); for the history-editing check itself (the three-step check, the append-only edit table, compaction shapes), Breaking change 3 in the same section
Prompt caching / optimize caching / "why is my cache hit rate low":
-> Read shared/prompt-caching.md (prefix-stability design, breakpoint placement, anti-patterns that silently invalidate cache) + {lang}/claude-api/README.md (Prompt Caching section)
Auditing or cleaning up prompts, skills, or tool descriptions ("is this prompt outdated", "remove the cruft", "this was written for an older model"):
-> Read shared/prompt-audit.md - dated-pattern tables with greppable signals, the keep list (what NOT to delete), and the report + proposed-diff output contract
Count tokens in a file / prompt / diff ("how many tokens is X"):
-> Read shared/token-counting.md - use messages.count_tokens, never tiktoken
Reducing or reviewing API spend ("the bill is too high", "make this cheaper", "am I overspending", cost per completed task, cheapest model or effort that holds quality):
-> Read shared/cost-optimization.md - baseline and token profile first, then the levers in order (free wins before tradeoffs) with measured expectations, and a workload-shape -> lever mapping table
Function calling / tool use / agents:
-> Read {lang}/claude-api/README.md + shared/tool-use-concepts.md (conceptual foundations: function calling, code execution, memory, structured outputs) + {lang}/claude-api/tool-use.md (language-specific code examples: tool runner, manual loop, code execution, memory, structured outputs)
Agent design (tool surface, context management, caching strategy):
-> Read shared/agent-design.md (bash vs. dedicated tools, programmatic tool calling, tool search/skills, context editing vs. compaction vs. memory, caching principles)
Batch processing (non-latency-sensitive; runs asynchronously at 50% cost):
-> Read {lang}/claude-api/README.md + {lang}/claude-api/batches.md
File uploads across multiple requests (same file without re-uploading):
-> Read {lang}/claude-api/README.md + {lang}/claude-api/files-api.md
Organization administration (members, invites, workspaces, API keys, rate limit reports, service accounts, WIF resources, CMEK):
-> Read shared/admin-api.md - client.beta.organization endpoint/method table, admin credentials, per-language naming and pagination, what stays curl-only
Debugging HTTP errors or implementing error handling:
-> Read shared/error-codes.md - per-SDK typed exception class table and the Go errors.As pattern
Latest official documentation:
-> WebFetch the URLs in shared/live-sources.md
Managed Agents (server-managed stateful agents with workspace):
-> See the reading guide in the ## Managed Agents (Beta) section above - it lists every shared/managed-agents-*.md file and the language-specific READMEs ({lang}/managed-agents/README.md, curl/managed-agents.md).
When to Use WebFetch
Use WebFetch to get the latest documentation when:
- User asks for "latest" or "current" information
- Cached data seems incorrect
- User asks about features not covered here
Live documentation URLs are in shared/live-sources.md.
Common Pitfalls
- Don't truncate inputs when passing files or content to the API. If the content is too long to fit in the context window, notify the user and discuss options (chunking, summarization, etc.) rather than silently truncating.
- Prefill removed (Fable 5, Claude Fable 5.1, Opus 5, Sonnet 5, and the 4.6/4.7/4.8 family): Assistant message prefills (last-assistant-turn prefills) return a 400 error on Fable 5, Claude Fable 5.1, Opus 5, Sonnet 5, Opus 4.6, Opus 4.7, Opus 4.8, and Sonnet 4.6. Use structured outputs (
output_config.format) or system prompt instructions to control response format instead. (One exception: the fallback-credit prefill claim - when redeeming a credit withfallback_has_prefill_claim: true, the server accepts the echoed assistant message; see the migration guide's refusal section.) - Confirm migration scope before editing: When a user asks to migrate code to a newer Claude model without naming a specific file, directory, or file list, ask which scope to apply first - the entire working directory, a specific subdirectory, or a specific set of files. Do not start editing until the user confirms. Imperative phrasings like "migrate my codebase", "move my project to X", "upgrade to Sonnet 4.6", or bare "migrate to Opus 4.8" are still ambiguous - they tell you what to do but not where, so ask. Proceed without asking only when the prompt names an exact file, a specific directory, or an explicit file list ("migrate
app.py", "migrate everything underservices/", "updatea.pyandb.py"). Seeshared/model-migration.mdStep 0. max_tokensdefaults: Don't lowballmax_tokens- hitting the cap truncates output mid-thought and requires a retry. For non-streaming requests, default to~16000(keeps responses under SDK HTTP timeouts). For streaming requests, default to~64000(timeouts aren't a concern, so give the model room). Only go lower when you have a hard reason: classification (~256), cost caps, deliberately short outputs, ormax_tokens: 0for cache pre-warming (seeshared/prompt-caching.md-> Pre-warming).- Disabling thinking on Claude Opus 5 has two failure modes - prefer low/medium effort instead. Only affects code that explicitly opts out; thinking is on by default, so watch for a disabled-thinking setting carried forward from Opus 4.8. With
thinking: {type: "disabled"}, the model occasionally writes a tool call into its visible text instead of atool_useblock: the turn succeeds, the call never runs, no error is raised, and in an agentic loop that text pollutes later turns. It can also leak<thinking>tags into the response. Turning thinking on and loweringeffortfixes both and still cuts cost. If a route must stay thinking-off: delete any don't-think/don't-reason rule (it makes tag leakage worse), don't name thinking tags, and add the combined instruction "When you use a tool, you may say a brief sentence first. If no tool can express what the user asked for, say so instead of guessing. Do not include internal or system XML tags in your response." Details:shared/model-migration.md-> Two failure modes when thinking is disabled. - 128K output tokens: Fable 5, Claude Fable 5.1, Opus 5, Opus 4.6, Opus 4.7, Opus 4.8, Sonnet 5, and Sonnet 4.6 support up to 128K
max_tokens, but the SDKs require streaming for values that large to avoid HTTP timeouts. Use.stream()with.get_final_message()/.finalMessage(). - Forced tool use removed (Claude Fable 5.1 / Claude Mythos 5.1, as on Mythos Preview):
tool_choice: {type: "any"}and{type: "tool", name: ...}return a 400 (tool_choice: type "tool" and "any" are not supported for this model.), oncount_tokensand Batches too. Use{type: "auto"}plus an explicit instruction naming the tool,strict: trueon the tool to keep schema-valid arguments, or structured outputs (output_config.format) when the forced call only existed to get JSON back.{type: "none"}is unaffected;disable_parallel_tool_usestill works withauto(at most one call). - Tool call JSON parsing (Fable 5, Claude Fable 5.1, Opus 5, and the 4.6/4.7/4.8 family): Fable 5, Claude Fable 5.1, Opus 5, Opus 4.6, Opus 4.7, Opus 4.8, and Sonnet 4.6 may produce different JSON string escaping in tool call
inputfields (e.g., Unicode or forward-slash escaping). Always parse tool inputs withjson.loads()/JSON.parse()- never do raw string matching on the serialized input. - Structured outputs (all models): Use
output_config: {format: {...}}instead of the deprecatedoutput_formatparameter onmessages.create(). This is a general API change, not 4.6-specific. - Don't reimplement SDK functionality: The SDK provides high-level helpers - use them instead of building from scratch. Specifically: use
stream.finalMessage()instead of wrapping.on()events innew Promise(); use typed exception classes (Anthropic.RateLimitError, etc.) instead of string-matching error messages; use SDK types (Anthropic.MessageParam,Anthropic.Tool,Anthropic.Message, etc.) instead of redefining equivalent interfaces. - Error handling - catch a chain, not one broad class. A single
except APIStatusError/catch (AnthropicServiceException)/rescue APIErrorloses the distinction between retryable (429, >=500, network) and non-retryable (400/404) failures. Write a most-specific-first chain - e.g.NotFoundError->RateLimitError->APIStatusError->APIConnectionError(or the Go equivalent:errors.Asinto*anthropic.Errorthenswitch apierr.StatusCode { case 404: ...; case 429: ...; default: ... }). Per-language class names and namespaces are inshared/error-codes.md. - Don't research SDK types - write first. If a type name isn't shown in the documentation included in this skill, write the code file from the namespace/package tables in the language-specific doc and let the compiler's error point you to the right name. Do not spend turns on WebFetch, SDK-repo clones, or compiling-and-running a separate reflection program to discover type names before writing - produce the source file first, then fix what the compiler reports. A quick
strings/jar tf/javapagainst the installed SDK is acceptable for locating names (it returns in seconds), but don't escalate beyond that. A file with a wrong type name is recoverable; a session spent on discovery with no file written is not. - Bash and text editor tools are Anthropic-defined, schema-less. Declare
{"type": "bash_20250124", "name": "bash"}/{"type": "text_editor_20250728", "name": "str_replace_based_edit_tool"}- noinput_schema. A custom tool with your own schema named"bash"is a different tool. Handler paths and security checks are inshared/tool-use-concepts.md§ Client-Side Tools. - Advisor tool model pairing. The advisor tool's
modelmust be at least as capable as the request's top-levelmodel- e.g. executorclaude-sonnet-5-> advisorclaude-opus-4-8orclaude-opus-4-7. An invalid pair returns 400. Pairing table inshared/tool-use-concepts.md§ Advisor. Availability:shared/platform-availability.md. - Agent Skills != Managed Agents. To have Claude generate a
.pptx/.xlsx/etc. via Agent Skills, callclient.beta.messages.createwithcontainer={"skills": [...]}, thecode_execution_20260521tool, and thecode-execution-2025-08-25beta (Skills is out of beta - noskills-2025-10-02header needed). Do not useclient.beta.agents/sessions/environmentshere - those are the Managed Agents surface, not Agent Skills. - MCP connector needs both halves.
mcp_servers=[{type:"url", url, name}]alone is rejected as a validation error - also addtools=[{type:"mcp_toolset", mcp_server_name:<same name>}]with betamcp-client-2025-11-20. Availability:shared/platform-availability.md. inference_geois a direct top-level request parameter -client.messages.create(..., inference_geo="us")/.inferenceGeo("us"). Do not put it inextra_body/putAdditionalBodyProperty. (Messages API only - on Managed Agents,inference_geoinstead nests inside the agent'smodelobject, never top-level; seeshared/managed-agents-core.md§ Pinning inference geography.) Supported on Opus 4.6 / Sonnet 4.6 and later; availability:shared/platform-availability.md.response.usage.inference_georeports where inference ran.- Fine-grained tool streaming is not a beta feature. Set
eager_input_streaming: trueon the tool definition and call the regularclient.messages.stream(...). There is no beta header and noclient.beta.*path. - Cache diagnostics is beta. Use
client.beta.messages.*with betacache-diagnosis-2026-04-07. Passdiagnostics: {previous_message_id: null}on the first turn anddiagnostics: {previous_message_id: <previous response id>}on subsequent turns; the result is onresponse.diagnostics. Availability:shared/platform-availability.md. - Memory tool type is
memory_20250818. Declare{"type": "memory_20250818", "name": "memory"}. Go uses the beta-namespace type{OfMemoryTool20250818: &anthropic.BetaMemoryTool20250818Param{}}onclient.Beta.Messages.New; Python/TypeScript/Ruby/PHP/C# use the non-betaclient.messages.create; Java has both a non-betaMemoryTool20250818and a beta tool-runner path. Python/TypeScript provideBetaAbstractMemoryTool/betaMemoryToolhelpers for implementing the backend. - Use a model the feature actually supports. Some features are restricted to specific model tiers - fast mode is Claude Opus 5 / Opus 4.8 only (and Claude API only), task budgets (Messages API only - Managed Agents session budgets have no model-tier restriction) are Claude Opus 5 / Fable 5 / Claude Fable 5.1 (confirm at launch) / Sonnet 5 / Opus 4.8 / 4.7 only, and the advisor tool requires a valid executor<->advisor pair. If the user's prompt names a model that the feature doesn't support, use a supported model instead and note the substitution in the output.
- Don't define custom types for SDK data structures: The SDK exports types for all API objects. Use
Anthropic.MessageParamfor messages,Anthropic.Toolfor tool definitions,Anthropic.ToolUseBlock/Anthropic.ToolResultBlockParamfor tool results,Anthropic.Messagefor responses. Defining your owninterface ChatMessage { role: string; content: unknown }duplicates what the SDK already provides and loses type safety. - Report and document output: For tasks that produce reports, documents, or visualizations, the code execution sandbox has
python-docx,python-pptx,matplotlib,pillow, andpypdfpre-installed. Claude can generate formatted files (DOCX, PDF, charts) and return them via the Files API - consider this for "report" or "document" type requests instead of plain stdout text. - Server-tool errors don't raise. Web search and web fetch errors return HTTP 200 with a
web_search_tool_result/web_fetch_tool_resultblock whosecontentis a single error object (e.g.{error_code: "max_uses_exceeded"}) - not a raised exception. For web search, a successcontentis a list; an errorcontentis an object - branch on that before indexing. - Managed Agents web tools ignore the environment's
networking.web_search/web_fetchrun on Anthropic's servers in cloud and self-hosted environments, and Console org-level web settings apply to the Messages API only. Restrict them per tool withallowed_domainsorblocked_domains(never both; 1-64 plain hostnames per list, subdomains covered; IPs, bare TLDs, single-label andlocalhost-style names rejected on both tools; a path suffix is allowed only onweb_search) on the toolsetconfigsentry -shared/managed-agents-tools.md§ Web search & web fetch settings. - Code execution output block type:
code_execution_20260521returnsbash_code_execution_tool_result(with.content.stdout), not the legacy barecode_execution_tool_result. Iterateresponse.contentand match on the correct type. - Tool search: never defer everything. The search tool itself must not have
defer_loading: true, and at least one tool intoolsmust be non-deferred, or the API returns 400All tools have defer_loading set.
Other files in this skill
- LICENSE.txt
- csharp/claude-api/README.md
- csharp/claude-api/batches.md
- csharp/claude-api/files-api.md
- csharp/claude-api/streaming.md
- csharp/claude-api/tool-use.md
- curl/examples.md
- curl/managed-agents.md
- go/claude-api/README.md
- go/claude-api/files-api.md
- go/claude-api/streaming.md
- go/claude-api/tool-use.md
- go/managed-agents/README.md
- java/claude-api/README.md
- java/claude-api/files-api.md
- java/claude-api/streaming.md
- java/claude-api/tool-use.md
- java/managed-agents/README.md
- php/claude-api/README.md
- php/claude-api/batches.md
- php/claude-api/files-api.md
- php/claude-api/streaming.md
- php/claude-api/tool-use.md
- php/managed-agents/README.md
- python/claude-api/README.md
- python/claude-api/batches.md
- python/claude-api/files-api.md
- python/claude-api/sdk-upgrade.md
- python/claude-api/streaming.md
- python/claude-api/tool-use.md
- python/managed-agents/README.md
- ruby/claude-api/README.md
- ruby/claude-api/streaming.md
- ruby/claude-api/tool-use.md
- ruby/managed-agents/README.md
- shared/admin-api.md
- shared/agent-design.md
- shared/anthropic-cli.md
- shared/claude-platform-on-aws.md
- shared/cost-optimization.md
- shared/error-codes.md
- shared/live-sources.md
- shared/managed-agents-api-reference.md
- shared/managed-agents-client-patterns.md
- shared/managed-agents-core.md
- shared/managed-agents-environments.md
- shared/managed-agents-events.md
- shared/managed-agents-memory.md
- shared/managed-agents-multiagent.md
- shared/managed-agents-onboarding.md
- shared/managed-agents-outcomes.md
- shared/managed-agents-overview.md
- shared/managed-agents-scheduled-deployments.md
- shared/managed-agents-self-hosted-sandboxes.md
- shared/managed-agents-tools.md
- shared/managed-agents-webhooks.md
- shared/model-migration.md
- shared/models.md
- shared/platform-availability.md
- shared/prompt-audit.md
- ... and 9 more (see the folder)
csharp/claude-api/README.md (verbatim)
1 placeholder credential shortened to pass the site's secret filter.
Claude API - C#
Note: The C# SDK is the official Anthropic SDK for C#. Tool use is supported via the Messages API with a beta
BetaToolRunnerfor automatic tool execution loops. The SDK also supports Microsoft.Extensions.AI IChatClient integration with function invocation and Managed Agents (beta).
Namespace Reference
Types are organized by namespace. If a type you need isn't shown in an example below, locate it via this table first - don't block on fetching SDK source over the network.
using |
Contains |
|---|---|
Anthropic |
AnthropicClient, top-level options |
Anthropic.Models.Messages |
non-beta request/response types - MessageCreateParams, Model, Role, ContentBlock, TextBlock, ToolUseBlock, ToolResultBlockParam, Tool* (tool definition classes) |
Anthropic.Models.Beta.Messages |
beta-endpoint equivalents - MessageCreateParams, BetaMessage, BetaTool*, Speed, BetaRequestMcpServerUrlDefinition, context-editing/compaction configs |
Anthropic.Models.Beta |
shared beta constants |
Anthropic.Models.Beta.Files |
Files API types |
Anthropic.Models.Messages.Batches |
Batch API types |
Anthropic.Helpers.Beta |
BetaToolRunner, beta helper utilities |
Anthropic.Exceptions |
AnthropicApiException, AnthropicRateLimitException, Anthropic5xxException, etc. - see shared/error-codes.md |
Anthropic.Bedrock / Anthropic.Vertex / Anthropic.Foundry / Anthropic.Aws |
platform clients (separate NuGet packages): AnthropicBedrockMantleClient, AnthropicFoundryClient, AnthropicAwsClient |
client.Messages.* uses non-beta types; client.Beta.Messages.* uses the Anthropic.Models.Beta.Messages types. Both namespaces define a MessageCreateParams - pick the one matching the client path you call.
Key types per feature
Write from this table instead of reflecting the SDK assembly. Endpoint column tells you whether to use client.Messages.* or client.Beta.Messages.*.
| Feature | Endpoint | Key C# types (namespace per table above) |
|---|---|---|
| User profiles | beta | client.Beta.UserProfiles.Create(...) / .Retrieve(id) / .List(). Pass the returned profile id on the beta messages call. Requires a beta header - check the SDK's beta-headers reference for the current flag. |
| Agent Skills | beta | BetaContainerParams (with Skills = [new BetaSkillParams { ... }]), BetaCodeExecutionTool20250825. Betas = ["code-execution-2025-08-25"] (Skills is out of beta - no skills-2025-10-02). Download the output via client.Beta.Files.Download(fileId). |
| Advisor tool | beta | BetaAdvisorTool20260301 - may not be in all SDK releases yet |
| Cache diagnostics | beta | Diagnostics = new() { PreviousMessageID = ... }, BetaCacheControlEphemeral, BetaContentBlockParam |
| Context editing | beta | ContextManagement = new BetaContextManagementConfig { Edits = [new BetaClearToolUses20250919Edit()] }. Betas = ["context-management-2025-06-27"] (not compact-2026-01-12 - that's for BetaCompact20260112Edit). |
| Memory tool | non-beta | Tools = [new ToolUnion(new MemoryTool20250818())] |
| Programmatic tool calling | non-beta | CodeExecutionTool20260120, ToolResultBlockParam, ContentBlockParam |
| Task budgets | beta | BetaOutputConfig with TaskBudget = new BetaTokenTaskBudget { ... } |
| Tool search | non-beta | new ToolUnion(new ToolSearchToolRegex20251119 { Type = ToolSearchToolRegex20251119Type.ToolSearchToolRegex20251119 }) - Type must be set explicitly. |
| Web search | non-beta | new ToolUnion(new WebSearchTool20260209()) - the latest variant with dynamic filtering (Claude Fable 5.1 + Claude Opus 5 + Opus 4.8/4.7/4.6 + Claude Sonnet 5 + Sonnet 4.6). For older models or Vertex, use WebSearchTool20250305() |
Discovering type and member names
If a type or member you need isn't in the tables above, strings ~/.nuget/packages/anthropic/*/lib/*/Anthropic.dll | grep -i <term> is fast and sufficient for locating class and property names. Do not escalate to a dotnet run reflection probe to dump members precisely - the first compile is slow enough to be backgrounded in many environments, trapping you in a polling loop. Instead, write Program.cs using the names strings | grep found; if a member name is wrong the compiler error (error CS1061: 'X' does not contain a definition for 'Y') points at it in a few seconds, faster than any reflection probe.
Note that strings will not surface wire-format snake_case field names (output_tokens, stop_reason) - those are stored in the DLL differently. C# properties are the PascalCase equivalent of the wire field (response.Usage.OutputTokens, response.StopReason). If you know the wire field name from the docs, write the PascalCase property and compile; do not probe for the snake_case string.
Minimal working skeleton
Write a plain Program.cs body - using statements followed by top-level statements, as below. Do not add a #!/usr/bin/env dotnet shebang or #:package Anthropic@* directive: those are .NET file-based-app syntax and fail with CS1024: Preprocessor directive expected when the file is compiled via an existing .csproj. The standard project setup (per the C# quickstart: dotnet new console -> dotnet add package Anthropic -> edit Program.cs -> dotnet run) provides the .csproj and package reference.
Start from this - it compiles as-is. Fill in the feature-specific fields; do not spend turns running reflection or XML-doc inspection to discover type names first.
using System;
using Anthropic;
using Anthropic.Models.Messages; // or Anthropic.Models.Beta.Messages for beta endpoints
AnthropicClient client = new();
var message = await client.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 1024,
Messages = [ new() { Role = Role.User, Content = "Hello, Claude" } ],
});
Console.WriteLine(message);
For beta features (anything behind an anthropic-beta header), use the beta client path and namespace - same overall shape:
using System;
using Anthropic;
using Anthropic.Models.Beta.Messages;
AnthropicClient client = new();
var response = await client.Beta.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 4096,
Betas = ["<beta-flag>"],
Messages = [ new() { Role = Role.User, Content = "..." } ],
// Tools = new BetaToolUnion[] { new BetaSomeTool { ... } }, // for tool features
});
Console.WriteLine(response);
If a type name the feature needs isn't in this file, write it following the naming pattern in the Namespace Reference above and fix from compiler output - producing a Program.cs and iterating beats researching.
Common C# compile errors
- CS8803 (top-level statements must precede type declarations): put any
record/class/structdefinitions after the last top-level statement, at the end of the file. A record defined abovevar client = new AnthropicClient()will not compile. await foreachon aTask<...Page>:client.Models.List()returns aTask<ModelListPage>, which is not directly async-enumerable. Await it first, then iterate:var page = await client.Models.List(); foreach (var m in page.Items) {...}. For auto-pagination, check whether the page type exposesAutoPagingEachAsync()or similar before reaching forawait foreach.
Installation
dotnet add package Anthropic
Client Initialization
using Anthropic;
// Default (uses ANTHROPIC_API_KEY env var)
AnthropicClient client = new();
// Explicit API key (use environment variables - never hardcode keys)
AnthropicClient client = new() {
ApiKey = YOUR_KEY
};
Basic Message Request
using Anthropic.Models.Messages;
var parameters = new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 16000,
Messages = [new() { Role = Role.User, Content = "What is the capital of France?" }]
};
var response = await client.Messages.Create(parameters);
// ContentBlock is a union wrapper. .Value unwraps to the variant object,
// then OfType<T> filters to the type you want. Or use the TryPick* idiom
// shown in the Thinking section below.
foreach (var text in response.Content.Select(b => b.Value).OfType<TextBlock>())
{
Console.WriteLine(text.Text);
}
Thinking
Adaptive thinking is the recommended mode for Claude 4.6+ models. Claude decides dynamically when and how much to think.
Fable 5, Claude Opus 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6: Use adaptive thinking (below).
new ThinkingConfigEnabled { BudgetTokens = N }is removed on Fable 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: thinking is on by default - omittingThinkingruns adaptive (ThinkingConfigAdaptiveis equivalent), unlike Opus 4.8/4.7 where omitting it meant no thinking.ThinkingConfigDisabledis accepted only at efforthighor lower; pairing it withxhigh/maxreturns a 400. Older models: Usenew ThinkingConfigEnabled { BudgetTokens = N }(budget must be <MaxTokens, min 1024).
using Anthropic.Models.Messages;
var response = await client.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 16000,
// ThinkingConfigParam? implicitly converts from the concrete variant classes -
// no wrapper needed.
// display opt-in: default is omitted (empty thinking text) on Fable 5 / Mythos 5 / Claude Opus 5 / Opus 4.8 / 4.7
Thinking = new ThinkingConfigAdaptive { Display = Display.Summarized },
Messages =
[
new() { Role = Role.User, Content = "Solve: 27 * 453" },
],
});
// ThinkingBlock(s) precede TextBlock in Content. TryPick* narrows the union.
foreach (var block in response.Content)
{
if (block.TryPickThinking(out ThinkingBlock? t))
{
Console.WriteLine($"[thinking] {t.Thinking}");
}
else if (block.TryPickText(out TextBlock? text))
{
Console.WriteLine(text.Text);
}
}
Alternative to TryPick*: .Select(b => b.Value).OfType<ThinkingBlock>() (same LINQ pattern as the Basic Message example).
Context Editing / Compaction (Beta)
Beta-namespace prefix is inconsistent (source-verified against src/Anthropic/Models/Beta/Messages/*.cs @ 12.9.0). No prefix: MessageCreateParams, MessageCountTokensParams, Role, Speed. Everything else has the Beta prefix: BetaMessageParam, BetaMessage, BetaContentBlock, BetaToolUseBlock, all block param types. The unprefixed Role WILL collide with Anthropic.Models.Messages.Role if you import both namespaces (CS0104). Safest: import only Beta; if mixing, alias the beta Role:
using Anthropic.Models.Beta.Messages;
using NonBeta = Anthropic.Models.Messages; // only if you also need non-beta types
// Now: MessageCreateParams, BetaMessageParam, Role (beta's), NonBeta.Role (if needed)
BetaMessage.Content is IReadOnlyList<BetaContentBlock> - a 15-variant discriminated union. Narrow with TryPick*. Response BetaContentBlock is NOT assignable to param BetaContentBlockParam - there's no .ToParam() in C#. Round-trip by converting each block:
using Anthropic.Models.Beta.Messages;
var betaParams = new MessageCreateParams // no Beta prefix - see unprefixed list above
{
Model = "claude-opus-5",
MaxTokens = 16000,
Betas = ["compact-2026-01-12"],
ContextManagement = new BetaContextManagementConfig
{
Edits = [new BetaCompact20260112Edit()],
},
Messages = messages,
};
BetaMessage resp = await client.Beta.Messages.Create(betaParams);
foreach (BetaContentBlock block in resp.Content)
{
if (block.TryPickCompaction(out BetaCompactionBlock? compaction))
{
// Content is nullable - compaction can fail server-side
Console.WriteLine($"compaction summary: {compaction.Content}");
}
}
// Context-edit metadata lives on a separate nullable field
if (resp.ContextManagement is { } ctx)
{
foreach (var edit in ctx.AppliedEdits)
Console.WriteLine($"cleared {edit.ClearedInputTokens} tokens");
}
// ROUND-TRIP: BetaMessageParam.Content is BetaMessageParamContent (a string|list
// union). It implicit-converts from List<BetaContentBlockParam>, NOT from the
// response's IReadOnlyList<BetaContentBlock>. Convert each block:
List<BetaContentBlockParam> paramBlocks = [];
foreach (var b in resp.Content)
{
if (b.TryPickText(out var t)) paramBlocks.Add(new BetaTextBlockParam { Text = t.Text });
else if (b.TryPickCompaction(out var c)) paramBlocks.Add(new BetaCompactionBlockParam { Content = c.Content });
// ... other variants as needed
}
messages.Add(new BetaMessageParam { Role = Role.Assistant, Content = paramBlocks });
All 15 BetaContentBlock.TryPick* variants: Text, Thinking, RedactedThinking, ToolUse, ServerToolUse, WebSearchToolResult, WebFetchToolResult, CodeExecutionToolResult, BashCodeExecutionToolResult, TextEditorCodeExecutionToolResult, ToolSearchToolResult, McpToolUse, McpToolResult, ContainerUpload, Compaction.
BetaToolUseBlock.Input is IReadOnlyDictionary<string, JsonElement> - index by key then call the JsonElement extractor:
if (block.TryPickToolUse(out BetaToolUseBlock? tu))
{
int a = tu.Input["a"].GetInt32();
string s = tu.Input["name"].GetString()!;
}
Effort Parameter
Effort is nested under OutputConfig, NOT a top-level property. ApiEnum<string, Effort> has an implicit conversion from the enum, so assign Effort.High directly.
OutputConfig = new OutputConfig { Effort = Effort.High },
Values: Effort.Low, Effort.Medium, Effort.High, Effort.Max. Combine with Thinking = new ThinkingConfigAdaptive() for cost-quality control.
Prompt Caching
System takes MessageCreateParamsSystem? - a union of string or List<TextBlockParam>. There is no SystemTextBlockParam; use plain TextBlockParam. The implicit conversion needs the concrete List<TextBlockParam> type (array literals won't convert). For placement patterns and the silent-invalidator audit checklist, see shared/prompt-caching.md.
System = new List<TextBlockParam> {
new() {
Text = longSystemPrompt,
CacheControl = new CacheControlEphemeral(), // auto-sets Type = "ephemeral"
},
},
Optional Ttl on CacheControlEphemeral: new() { Ttl = Ttl.Ttl1h } or Ttl.Ttl5m. CacheControl also exists on Tool.CacheControl and top-level MessageCreateParams.CacheControl.
Verify hits via response.Usage.CacheCreationInputTokens / response.Usage.CacheReadInputTokens.
Token Counting
MessageTokensCount result = await client.Messages.CountTokens(new MessageCountTokensParams {
Model = "claude-opus-5",
Messages = [new() { Role = Role.User, Content = "Hello" }],
});
long tokens = result.InputTokens;
MessageCountTokensParams.Tools uses a different union type (MessageCountTokensTool) than MessageCreateParams.Tools (ToolUnion) - if you're passing tools, the compiler will tell you when it matters.
PDF / Document Input
DocumentBlockParam takes a DocumentBlockParamSource union: Base64PdfSource / UrlPdfSource / PlainTextSource / ContentBlockSource. Base64PdfSource auto-sets MediaType = "application/pdf" and Type = "base64".
new MessageParam {
Role = Role.User,
Content = new List<ContentBlockParam> {
new DocumentBlockParam { Source = new Base64PdfSource { Data = base64String } },
new TextBlockParam { Text = "Summarize this PDF" },
},
}
Fast Mode (Beta)
var response = await client.Beta.Messages.Create(new MessageCreateParams {
Model = "claude-opus-5", MaxTokens = 4096,
Speed = Speed.Fast,
Betas = ["fast-mode-2026-02-01"],
Messages = [...],
});
Models API
var page = await client.Models.List();
foreach (var m in page.Items) { Console.WriteLine(m.ID); }
var one = await client.Models.Retrieve("claude-opus-5");
Long Output (128k) + Prefill
Set MaxTokens = 128000 on client.Messages and use the streaming path (see streaming.md). On Claude 4+ models, 128k output is native - no output-128k-* beta header or beta namespace is needed.
Prefilling the assistant message (putting a trailing Role.Assistant message in the input) is not supported on Claude Fable 5.1, Claude Opus 5, Opus 4.8, Opus 4.7, Opus 4.6, and Sonnet 4.6 - requests return a 400. Use OutputConfig.Format (structured outputs) instead.
Stop Details
When StopReason is "refusal", the response includes structured StopDetails:
if (response.StopReason == "refusal" && response.StopDetails is { } details)
{
Console.WriteLine($"Category: {details.Category}");
Console.WriteLine($"Explanation: {details.Explanation}");
}
Refusal fallbacks (Claude Fable 5.1) - opt in by default. Fallbacks are opt-in: without them a refused request simply stops. In claude-fable-5-1 code, include Fallbacks = [new(Model.ClaudeOpus4_8)] plus the AnthropicBeta.ServerSideFallback2026_06_01 beta on the beta messages call by default - a policy decline is re-served by the fallback model inside the same call. Not available on Amazon Bedrock, Vertex AI, or Microsoft Foundry - use the client-side handler there: new AnthropicClient { Handlers = [new BetaRefusalFallbackHandler { Fallbacks = [new(Model.ClaudeOpus4_8)] }] } (namespace Anthropic.Helpers), with per-conversation state via BetaFallbackState.Create() scoped with using (fallbackState.Use()) { ... }. Full semantics (billing, sticky routing, streaming) and a runnable example: shared/model-migration.md -> Migrating to Claude Fable 5.1 -> refusal stop reason, and the C# SDK repo's examples/ (WebFetch via shared/live-sources.md).
Managed Agents (Beta)
The C# SDK supports Managed Agents via client.Beta.Agents, client.Beta.Sessions, client.Beta.Environments, and related namespaces. See shared/managed-agents-overview.md for the architecture and curl/managed-agents.md for the wire-level reference.
csharp/claude-api/batches.md (verbatim)
Message Batches - C#
Message Batches API
var batch = await client.Messages.Batches.Create(new() {
Requests = [
new() { CustomID = "req-1", Params = new() { Model = "claude-opus-5", MaxTokens = 1024, Messages = [...] } },
],
});
// Poll client.Messages.Batches.Retrieve(batch.ID) until ProcessingStatus == "ended",
// then iterate client.Messages.Batches.Results(batch.ID).
csharp/claude-api/files-api.md (verbatim)
Files API - C#
Files API
Out of beta. In current SDKs
client.Beta.Fileshas breaking shape changes from previous versions, matching the stableclient.Files- migrate per the Files API row inshared/live-sources.md. Examples below predate this.
Files live under client.Beta.Files (namespace Anthropic.Models.Beta.Files). BinaryContent implicit-converts from Stream and byte[].
using Anthropic.Models.Beta.Files;
using Anthropic.Models.Beta.Messages;
FileMetadata meta = await client.Beta.Files.Upload(
new FileUploadParams { File = File.OpenRead("doc.pdf") });
// Referencing the uploaded file requires Beta message types:
new BetaRequestDocumentBlock {
Source = new BetaFileDocumentSource { FileID = meta.ID },
}
The non-beta DocumentBlockParamSource union has no file-ID variant - file references need client.Beta.Messages.Create().
csharp/claude-api/streaming.md (verbatim)
Streaming - C#
Streaming
using Anthropic.Models.Messages;
var parameters = new MessageCreateParams
{
Model = Model.ClaudeOpus4_8,
MaxTokens = 64000,
Messages = [new() { Role = Role.User, Content = "Write a haiku" }]
};
await foreach (RawMessageStreamEvent streamEvent in client.Messages.CreateStreaming(parameters))
{
if (streamEvent.TryPickContentBlockDelta(out var delta) &&
delta.Delta.TryPickText(out var text))
{
Console.Write(text.Text);
}
}
RawMessageStreamEvent TryPick methods (naming drops the Message/Raw prefix): TryPickStart, TryPickDelta, TryPickStop, TryPickContentBlockStart, TryPickContentBlockDelta, TryPickContentBlockStop. There is no TryPickMessageStop - use TryPickStop.
php/claude-api/batches.md (verbatim)
Message Batches - PHP
Message Batches API
$batch = $client->messages->batches->create(requests: [
['customId' => 'req-1', 'params' => ['model' => 'claude-opus-5', 'maxTokens' => 1024, 'messages' => [...]]],
['customId' => 'req-2', 'params' => [...]],
]);
// Poll $client->messages->batches->retrieve($batch->id) until processingStatus === 'ended',
// then iterate $client->messages->batches->results($batch->id).
Back to anthropics/skills (Anthropic official skills) or Agent skills.