Learning Logs · · 3 min read
Learning the Claude API: from API key to streaming
The Claude API with the official TypeScript SDK: API-key setup, first call, system prompts for CS chatbots, multi-turn conversations, streaming, and choosing a model.
Claude is Anthropic’s AI model — the one I use in nearly every client AI feature: CS chatbots, RAG, and agents. This tutorial goes from getting an API key to streaming, using the official TypeScript/JavaScript SDK.
1. Setup
- Create an account at platform.claude.com, then create an API key in the Console.
- Store it as an environment variable — never put the key in code:
export ANTHROPIC_API_KEY="sk-ant-..." # Windows (PowerShell): $env:ANTHROPIC_API_KEY="sk-ant-..."
- Install the official SDK:
npm install @anthropic-ai/sdk
2. Your first call
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // reads ANTHROPIC_API_KEY automatically
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 16000,
messages: [{ role: "user", content: "Explain RAG in 3 sentences, for an online store owner." }],
});
// content is an array of blocks — filter for text blocks before reading .text
for (const block of response.content) {
if (block.type === "text") console.log(block.text);
}
Two important details: max_tokens is an upper bound on output (not a target), and response.content is an array of typed blocks — always check block.type first.
3. System prompts: personality & rules
const response = await client.messages.create({
model: "claude-opus-4-8",
max_tokens: 16000,
system:
"You are customer support for 'Gayo Store', a coffee shop. Answer warmly and concisely. " +
"If asked about off-topic things, politely redirect. Never invent stock levels or prices.",
messages: [{ role: "user", content: "Which arabica is your best seller?" }],
});
The system prompt is where business rules live — this is 80% of the work of building a good chatbot.
4. Multi-turn conversations
The API is stateless: send the full history every time.
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "My name is Budi, I sell coffee." },
{ role: "assistant", content: "Hi Budi! Nice to meet you." },
{ role: "user", content: "What's my name and what do I sell?" },
];
const response = await client.messages.create({
model: "claude-opus-4-8", max_tokens: 16000, messages,
});
5. Streaming — mandatory for chat UIs
Without streaming, users stare at a blank screen until the answer finishes. With it, text flows word by word:
const stream = client.messages.stream({
model: "claude-opus-4-8",
max_tokens: 16000,
messages: [{ role: "user", content: "Write a product description for 250g Gayo coffee." }],
});
stream.on("text", (delta) => process.stdout.write(delta));
const final = await stream.finalMessage(); // complete message + token usage
console.log("\nOutput tokens:", final.usage.output_tokens);
6. Choosing a model
| Model | ID | When to use |
|---|---|---|
| Claude Opus 4.8 | claude-opus-4-8 |
My default — strongest reasoning for agents & complex tasks |
| Claude Sonnet 5 | claude-sonnet-5 |
The speed/cost balance for coding & chatbots |
| Claude Haiku 4.5 | claude-haiku-4-5 |
High-volume light tasks: classification, routing |
Per-token pricing differs by model — check the official pricing page; real costs only stay under control if you watch response.usage from day one.
Tips from experience
- Handle errors with the SDK’s typed exception classes (
Anthropic.RateLimitError, etc.) — never string-match error messages. - For store chatbots, answers must be grounded in data (RAG) — any model will hallucinate if asked to answer stock questions from memory. See the NexaMart case-study docs on this site.
- In production, keep the API key in a secret manager (on Cloudflare Workers:
wrangler secret put), not in a committed.envfile.
Want something like this built for your business?