Anthropic Claude Free code examples in C#, Python, Java and JavaScript
Claude models with long context, tool use and prompt caching.
Try it without writing code: Prompt Generator, Document Summarizer, Prompt Testing Kit — free in the browser.
Using Claude Code? Free subagents, skills, hooks and MCP server templates are in the Claude Kit.
WHAT THIS PAGE COVERS
Messages API basics, then prompt caching — the single biggest cost lever.
claude-opus-5
anthropic
Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.
The official Anthropic package for .NET.
dotnet add package Anthropic
setx ANTHROPIC_API_KEY "sk-ant-..."
The zero-argument constructor reads ANTHROPIC_API_KEY. ContentBlock is a union — .Value unwraps it, so OfType<TextBlock>() gives you just the text blocks.
using Anthropic;
using Anthropic.Models.Messages;
AnthropicClient client = new();
var response = await client.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 16000,
System = "You are a concise technical assistant.",
Messages =
[
new() { Role = Role.User, Content = "Explain a database index in two sentences." },
],
});
foreach (var text in response.Content.Select(b => b.Value).OfType<TextBlock>())
{
Console.WriteLine(text.Text);
}
Console.WriteLine($"{response.Usage.InputTokens} in, {response.Usage.OutputTokens} out");
TryPick narrows the event union. Note the naming: there is no TryPickMessageStop — it is TryPickStop.
using Anthropic.Models.Messages;
var parameters = new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 64000,
Messages = [new() { Role = Role.User, Content = "Write a haiku about indexes." }],
};
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);
}
}
Console.WriteLine();
System takes a union of string or List<TextBlockParam>. The implicit conversion needs the concrete List<T> — an array literal will not compile here.
using Anthropic.Models.Messages;
string document = await File.ReadAllTextAsync("handbook.md"); // stable context
async Task<Message> Ask(string question) =>
await client.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 16000,
System = new List<TextBlockParam>
{
new()
{
Text = document,
CacheControl = new CacheControlEphemeral(), // 5-minute TTL
},
},
Messages = [new() { Role = Role.User, Content = question }],
});
var first = await Ask("What is the leave policy?");
var second = await Ask("And the notice period?");
// Proof it worked. Stuck at 0 means something in the prefix varies.
Console.WriteLine($"wrote {first.Usage.CacheCreationInputTokens}");
Console.WriteLine($"read {second.Usage.CacheReadInputTokens}");
ThinkingConfigAdaptive, not a budget. Effort is nested under OutputConfig, never a top-level property.
using Anthropic.Models.Messages;
var response = await client.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 16000,
Thinking = new ThinkingConfigAdaptive { Display = Display.Summarized },
OutputConfig = new OutputConfig { Effort = Effort.High },
Messages = [new() { Role = Role.User, Content = "Plan a zero-downtime migration." }],
});
foreach (var block in response.Content)
{
if (block.TryPickThinking(out ThinkingBlock? thinking))
Console.WriteLine($"[thinking] {thinking.Thinking}");
else if (block.TryPickText(out TextBlock? text))
Console.WriteLine(text.Text);
}
// A refusal returns HTTP 200 — StopDetails is null for every other reason.
if (response.StopReason == "refusal" && response.StopDetails is { } details)
{
Console.WriteLine($"Declined: {details.Category}");
}
Typed exceptions under Anthropic.Exceptions. Catch the specific ones first so you can tell a retryable failure from a permanent one.
using Anthropic.Exceptions;
using Anthropic.Models.Messages;
try
{
var response = await client.Messages.Create(new MessageCreateParams
{
Model = "claude-opus-5",
MaxTokens = 16000,
Messages = [new() { Role = Role.User, Content = "..." }],
});
}
catch (AnthropicRateLimitException)
{
Console.Error.WriteLine("Rate limited — retry after a backoff.");
}
catch (Anthropic5xxException ex)
{
Console.Error.WriteLine($"Server error — safe to retry: {ex.Message}");
}
catch (AnthropicApiException ex)
{
Console.Error.WriteLine($"API error: {ex.Message}");
}
The client reads ANTHROPIC_API_KEY from the environment. It will also pick up an `ant auth login` profile, so an unset variable does not always mean no credentials.
pip install anthropic
export ANTHROPIC_API_KEY="sk-ant-..." # macOS / Linux
setx ANTHROPIC_API_KEY "sk-ant-..." # Windows, then open a new shell
max_tokens is required — unlike most APIs, there is no default. content is a list of blocks, not a string: check block.type before reading .text or you will crash the first time the model thinks.
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-5",
max_tokens=16000,
system="You are a concise technical assistant.",
messages=[
{"role": "user", "content": "Explain a database index in two sentences."},
],
)
for block in response.content:
if block.type == "text":
print(block.text)
print(response.usage.input_tokens, response.usage.output_tokens)
Use messages.stream(), not stream=True — the helper accumulates state and hands you the finished message at the end. Streaming is also how you avoid an HTTP timeout on a large max_tokens.
with client.messages.stream(
model="claude-opus-5",
max_tokens=64000,
messages=[{"role": "user", "content": "Write a haiku about indexes."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
final = stream.get_final_message()
print()
print(final.usage.output_tokens)
Caching is a PREFIX match: one changed byte anywhere before the breakpoint invalidates everything after it. Put the stable document first and the varying question last, or you will pay the write cost on every call and never get a read.
document = open("handbook.md").read() # e.g. 50 KB of stable context
def ask(question: str):
return client.messages.create(
model="claude-opus-5",
max_tokens=16000,
system=[{
"type": "text",
"text": document,
"cache_control": {"type": "ephemeral"}, # 5-minute TTL
}],
# The varying part goes AFTER the breakpoint.
messages=[{"role": "user", "content": question}],
)
first = ask("What is the leave policy?")
second = ask("And the notice period?")
# Proof it worked. If cache_read stays 0 across calls, something in the
# prefix is changing — a timestamp, a UUID, an unsorted json.dumps().
print("wrote :", first.usage.cache_creation_input_tokens)
print("read :", second.usage.cache_read_input_tokens)
On current models, thinking is adaptive — the model decides how much to do. A budget_tokens number is REJECTED with a 400, and effort lives inside output_config, not at the top level.
response = client.messages.create(
model="claude-opus-5",
max_tokens=16000,
thinking={"type": "adaptive", "display": "summarized"},
output_config={"effort": "high"}, # low | medium | high | xhigh | max
messages=[{"role": "user", "content": "Plan a zero-downtime migration."}],
)
for block in response.content:
if block.type == "thinking":
print("[thinking]", block.thinking)
elif block.type == "text":
print(block.text)
# Always check before trusting the text: a refusal returns HTTP 200.
if response.stop_reason == "refusal":
print("Declined:", response.stop_details.category)
elif response.stop_reason == "max_tokens":
print("Truncated — raise max_tokens.")
The SDK retries 429 and 5xx twice on its own. Catch what it cannot fix, and read retry-after rather than guessing a backoff.
import anthropic
try:
response = client.messages.create(
model="claude-opus-5",
max_tokens=16000,
messages=[{"role": "user", "content": "..."}],
)
except anthropic.AuthenticationError:
raise SystemExit("ANTHROPIC_API_KEY is missing or revoked.")
except anthropic.NotFoundError:
raise SystemExit("Unknown model id — check the official docs linked below.")
except anthropic.RateLimitError as e:
retry_after = int(e.response.headers.get("retry-after", "60"))
raise SystemExit(f"Rate limited; retry in {retry_after}s.")
except anthropic.APIStatusError as e:
raise SystemExit(f"API error {e.status_code}: {e.message}")
except anthropic.APIConnectionError:
raise SystemExit("Could not reach the API — check the network or proxy.")
The official Anthropic SDK for Java. Gradle: implementation("com.anthropic:anthropic-java:2.34.0").
<dependency>
<groupId>com.anthropic</groupId>
<artifactId>anthropic-java</artifactId>
<version>2.34.0</version>
</dependency>
fromEnv() reads ANTHROPIC_API_KEY. Use .model(String) rather than the typed Model constants — those ship with the SDK and lag a new model by a release or two.
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-opus-5")
.maxTokens(16000L)
.system("You are a concise technical assistant.")
.addUserMessage("Explain a database index in two sentences.")
.build();
Message response = client.messages().create(params);
response.content().stream()
.flatMap(block -> block.text().stream())
.forEach(textBlock -> System.out.println(textBlock.text()));
Close the stream — try-with-resources does it here. It holds an HTTP connection open, and leaking one per request stalls the pool long before you see an error.
import com.anthropic.core.http.StreamResponse;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.RawMessageStreamEvent;
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-opus-5")
.maxTokens(64000L)
.addUserMessage("Write a haiku about indexes.")
.build();
try (StreamResponse<RawMessageStreamEvent> stream =
client.messages().createStreaming(params)) {
stream.stream()
.flatMap(event -> event.contentBlockDelta().stream())
.flatMap(deltaEvent -> deltaEvent.delta().text().stream())
.forEach(textDelta -> System.out.print(textDelta.text()));
}
Caching is a PREFIX match. Put the stable document in the system blocks with the breakpoint, and the varying question in the user message after it.
import com.anthropic.models.messages.CacheControlEphemeral;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.TextBlockParam;
import java.nio.file.Files;
import java.nio.file.Path;
String document = Files.readString(Path.of("handbook.md")); // stable context
java.util.function.Function<String, Message> ask = question ->
client.messages().create(MessageCreateParams.builder()
.model("claude-opus-5")
.maxTokens(16000L)
.systemOfTextBlockParams(java.util.List.of(
TextBlockParam.builder()
.text(document)
.cacheControl(CacheControlEphemeral.builder().build())
.build()))
.addUserMessage(question)
.build());
Message first = ask.apply("What is the leave policy?");
Message second = ask.apply("And the notice period?");
// Proof it worked. Stuck at 0 means something in the prefix varies.
System.out.println("wrote " + first.usage().cacheCreationInputTokens());
System.out.println("read " + second.usage().cacheReadInputTokens());
ThinkingConfigAdaptive, not ThinkingConfigEnabled.budgetTokens — the budget form is rejected with a 400 on current models.
import com.anthropic.models.messages.ContentBlock;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.ThinkingConfigAdaptive;
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-opus-5")
.maxTokens(16000L)
.thinking(ThinkingConfigAdaptive.builder()
.display(ThinkingConfigAdaptive.Display.SUMMARIZED)
.build())
.addUserMessage("Plan a zero-downtime migration.")
.build();
Message response = client.messages().create(params);
for (ContentBlock block : response.content()) {
block.thinking().ifPresent(t -> System.out.println("[thinking] " + t.thinking()));
block.text().ifPresent(t -> System.out.println(t.text()));
}
Typed exceptions per status under com.anthropic.errors. Catch the specific ones first.
import com.anthropic.errors.AnthropicServiceException;
import com.anthropic.errors.NotFoundException;
import com.anthropic.errors.RateLimitException;
import com.anthropic.errors.UnauthorizedException;
import com.anthropic.models.messages.MessageCreateParams;
try {
client.messages().create(MessageCreateParams.builder()
.model("claude-opus-5")
.maxTokens(16000L)
.addUserMessage("...")
.build());
} catch (UnauthorizedException e) {
System.err.println("ANTHROPIC_API_KEY missing or revoked.");
} catch (NotFoundException e) {
System.err.println("Unknown model id — check the official docs linked below.");
} catch (RateLimitException e) {
System.err.println("Rate limited — retry after a backoff.");
} catch (AnthropicServiceException e) {
System.err.println("API error: " + e.getMessage());
}
Node 18 or newer. The client reads ANTHROPIC_API_KEY from process.env. Never ship a key to the browser.
npm install @anthropic-ai/sdk
export ANTHROPIC_API_KEY="sk-ant-..."
max_tokens is required. content is a discriminated union — TypeScript will refuse content[0].text until you narrow on .type, which is the compiler doing you a favour.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const response = await client.messages.create({
model: "claude-opus-5",
max_tokens: 16000,
system: "You are a concise technical assistant.",
messages: [
{ role: "user", content: "Explain a database index in two sentences." },
],
});
for (const block of response.content) {
if (block.type === "text") console.log(block.text);
}
console.log(response.usage.input_tokens, response.usage.output_tokens);
messages.stream() accumulates for you; finalMessage() resolves once the stream ends. Do not hand-roll a Promise around .on() — the helper already does it.
const stream = client.messages.stream({
model: "claude-opus-5",
max_tokens: 64000,
messages: [{ role: "user", content: "Write a haiku about indexes." }],
});
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("\n", final.usage.output_tokens);
Caching is a PREFIX match: one changed byte before the breakpoint invalidates everything after it. Stable content first, the varying question last.
import fs from "node:fs";
const document = fs.readFileSync("handbook.md", "utf8"); // stable context
async function ask(question) {
return client.messages.create({
model: "claude-opus-5",
max_tokens: 16000,
system: [{
type: "text",
text: document,
cache_control: { type: "ephemeral" }, // 5-minute TTL
}],
messages: [{ role: "user", content: question }],
});
}
const first = await ask("What is the leave policy?");
const second = await ask("And the notice period?");
// Proof it worked. A cache_read stuck at 0 means something in the prefix
// is changing — Date.now(), a UUID, non-deterministic key ordering.
console.log("wrote:", first.usage.cache_creation_input_tokens);
console.log("read :", second.usage.cache_read_input_tokens);
On current models thinking is adaptive. A budget_tokens number is REJECTED with a 400, and effort lives inside output_config.
const response = await client.messages.create({
model: "claude-opus-5",
max_tokens: 16000,
thinking: { type: "adaptive", display: "summarized" },
output_config: { effort: "high" }, // low | medium | high | xhigh | max
messages: [{ role: "user", content: "Plan a zero-downtime migration." }],
});
for (const block of response.content) {
if (block.type === "thinking") console.log("[thinking]", block.thinking);
else if (block.type === "text") console.log(block.text);
}
// A refusal returns HTTP 200 — check before trusting the text.
if (response.stop_reason === "refusal") {
console.warn("Declined:", response.stop_details?.category);
} else if (response.stop_reason === "max_tokens") {
console.warn("Truncated — raise max_tokens.");
}
Typed error classes, checked most specific first. Never match on message text.
import Anthropic from "@anthropic-ai/sdk";
try {
const response = await client.messages.create({
model: "claude-opus-5",
max_tokens: 16000,
messages: [{ role: "user", content: "..." }],
});
} catch (error) {
if (error instanceof Anthropic.AuthenticationError) {
console.error("ANTHROPIC_API_KEY missing or revoked.");
} else if (error instanceof Anthropic.NotFoundError) {
console.error("Unknown model id — check the official docs linked below.");
} else if (error instanceof Anthropic.RateLimitError) {
console.error("Rate limited — retry after a backoff.");
} else if (error instanceof Anthropic.APIError) {
console.error(`API error ${error.status}: ${error.message}`);
} else {
throw error;
}
}
QUESTIONS
Which languages are the Anthropic Claude examples in?
C#, Python, Java and JavaScript. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.
Which package do I install for Anthropic Claude?
The samples use anthropic. The install step on each language tab gives the exact command.
Which Anthropic Claude model do these examples use?
claude-opus-5, checked against the official documentation on 25 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.
Where is the official Anthropic Claude documentation?
https://docs.anthropic.com — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.
ALSO IN LANGUAGE MODELS
The authority
Official Anthropic Claude documentation
Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.
https://docs.anthropic.com