Claude API Cheat Sheet for TypeScript Developers
A one-page reference for the Messages API in TypeScript: request parameters, response fields, stop reasons, streaming events, errors, and the SDK helpers you use daily.
On this page· One request
Why this matters
You will look these things up constantly: which parameter controls what, what each stop_reason means, which errors to retry. This page collects them, with links to the articles that explain each one. Model names, limits, and features change; check the official documentation for current details before relying on a value.
One request#
Step 1 of 5
build request: model, max_tokens, system, messages
Everything the model needs for this task goes into this one request. The API key is added by the SDK from the environment.
Show text descriptionHide text description
The life of a single request, step by step. Participants, left to right: Your server, Messages API.
- Your server → Your server: build request: model, max_tokens, system, messages · Everything the model needs for this task goes into this one request. The API key is added by the SDK from the environment.
- Your server → Messages API: POST /v1/messages · The SDK sends the request over HTTPS, retrying automatically on rate limits and transient errors.
- Messages API → Messages API: generate tokens until a stop condition · The model writes (and possibly reasons) until it finishes, hits max_tokens, or wants a tool.
- Messages API → Your server: { content: [blocks], stop_reason, usage } · content is a list of typed blocks (text, thinking, tool_use); stop_reason says why generation ended; usage reports input and output tokens.
- Your server → Your server: check stop_reason, read text blocks, log usage · Branch on stop_reason before trusting the text, and record usage for cost tracking.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic(); // reads ANTHROPIC_API_KEY
const message = await client.messages.create({
model: "claude-opus-5-5",
max_tokens: 4096,
system: "You are a concise assistant.",
messages: [{ role: "user", content: "Explain idempotency in one paragraph." }],
});
console.log(message.content.flatMap((b) => (b.type === "text" ? [b.text] : [])).join(""));Request parameters#
| Parameter | Purpose | Notes |
|---|---|---|
model | Which model | claude-opus-5-5, claude-sonnet-5-5, claude-haiku-4-5 at the time of writing |
max_tokens | Output limit | Required; reaching it gives stop_reason: "max_tokens" |
messages | The conversation | Alternating user and assistant, starting with user; system messages allowed mid-conversation on current models |
system | Instructions | String or text blocks (blocks can carry cache_control) |
tools, tool_choice | Tool use | auto (default) or none; forced tool choice is not supported on the newest models |
output_config.format | Structured outputs | Use messages.parse with zodOutputFormat |
output_config.effort | Thoroughness vs. speed and tokens | low, medium, high (and higher on some models) |
thinking | Extended reasoning | { type: "adaptive" } on current models |
cache_control | Prompt caching | Top-level for automatic caching, or on blocks as breakpoints |
stream | Streaming | Prefer client.messages.stream() in the SDK |
temperature, top_p, and top_k are not accepted by the newest models; steer behavior with instructions, examples, and effort.
Response fields#
| Field | Meaning |
|---|---|
content | Array of blocks: text, tool_use, thinking, server tool results |
stop_reason | Why generation stopped (below) |
usage | input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens |
id, model | Message ID and the model that answered |
_request_id | Request ID for support (also error.requestID on errors) |
Stop reasons#
Hover or tap a component to see what it does.
Show text descriptionHide text description
Code that only reads the text of a response treats a truncated answer, a refusal, and a request for a tool as if they were complete answers. Branch on stop_reason first.
- Response: Every Messages API response says why generation stopped.
- end_turn: The model finished naturally. Read the text blocks.
- max_tokens: The answer hit your output limit and is incomplete. Raise max_tokens, ask for shorter output, or continue the response.
- tool_use: The model is waiting for your code to execute one or more tools and return tool_result blocks.
- refusal: The request was declined. Do not show partial output as an answer; show a clear message instead.
- pause_turn: A long server-side tool turn paused. Append the response and call again to continue.
stop_reason | Meaning | What to do |
|---|---|---|
end_turn | Finished naturally | Use the answer |
tool_use | Wants tools run | Run them, send tool_result blocks in one user message |
max_tokens | Hit the output limit | Raise max_tokens, ask for shorter output, or continue |
stop_sequence | Hit a custom stop sequence | Expected if you set one |
pause_turn | Server tools paused a long turn | Send the conversation back to continue |
refusal | Declined for safety reasons | Show a helpful message; do not retry blindly |
model_context_window_exceeded | Ran out of context | Trim history, compact, or retrieve less |
The same table as code, so every caller handles every case:
import type Anthropic from "@anthropic-ai/sdk";
export type NextAction =
| { kind: "answer"; text: string }
| { kind: "run_tools"; calls: Anthropic.ToolUseBlock[] }
| { kind: "continue" }
| { kind: "truncated"; partial: string }
| { kind: "refused" }
| { kind: "context_full" };
const textOf = (m: Anthropic.Message) => m.content.flatMap((b) => (b.type === "text" ? [b.text] : [])).join("");
export function nextAction(message: Anthropic.Message): NextAction {
switch (message.stop_reason) {
case "tool_use":
return { kind: "run_tools", calls: message.content.filter((b): b is Anthropic.ToolUseBlock => b.type === "tool_use") };
case "pause_turn":
return { kind: "continue" };
case "max_tokens":
return { kind: "truncated", partial: textOf(message) };
case "refusal":
return { kind: "refused" };
case "model_context_window_exceeded":
return { kind: "context_full" };
case "end_turn":
case "stop_sequence":
case null:
return { kind: "answer", text: textOf(message) };
default: {
// A new stop reason added in a future API version fails the type check here.
const unknown: never = message.stop_reason;
throw new Error(`Unhandled stop_reason: ${String(unknown)}`);
}
}
}import { test } from "node:test";
import assert from "node:assert/strict";
import type Anthropic from "@anthropic-ai/sdk";
import { nextAction } from "./lib/next-action.ts";
const msg = (stop_reason: Anthropic.StopReason, content: unknown[]) => ({ stop_reason, content }) as unknown as Anthropic.Message;
test("maps stop reasons to actions", () => {
assert.deepEqual(nextAction(msg("end_turn", [{ type: "text", text: "Hi" }])), { kind: "answer", text: "Hi" });
assert.equal(nextAction(msg("tool_use", [{ type: "tool_use", id: "t", name: "x", input: {} }])).kind, "run_tools");
assert.deepEqual(nextAction(msg("max_tokens", [{ type: "text", text: "Part" }])), { kind: "truncated", partial: "Part" });
assert.equal(nextAction(msg("pause_turn", [])).kind, "continue");
assert.equal(nextAction(msg("refusal", [])).kind, "refused");
});Streaming events#
| Event | Carries |
|---|---|
message_start | Message ID, model, initial usage |
content_block_start | A new block (text, tool use, thinking) |
content_block_delta | text_delta, input_json_delta (tool input), thinking_delta, citations_delta |
content_block_stop | Block finished |
message_delta | Final stop_reason and output usage |
message_stop | Done |
With the SDK: stream.on("text", …) for text, await stream.finalMessage() for the complete message. See streaming to React.
Errors#
| Status | Type | Retry? |
|---|---|---|
| 400 | invalid_request_error | No: fix the request |
| 401 / 403 | authentication_error / permission_error | No: check keys and access |
| 404 | not_found_error | No: check the model name or ID |
| 413 | Request too large | No: send less |
| 429 | rate_limit_error | Yes, after retry-after |
| 500 | api_error | Yes |
| 529 | overloaded_error | Yes, with backoff, then fall back |
The SDK retries retryable errors twice by default and throws typed errors (Anthropic.RateLimitError, Anthropic.BadRequestError, …). See reliability.
SDK helpers#
| Helper | Use it for |
|---|---|
client.messages.parse + zodOutputFormat | Typed structured outputs |
client.messages.stream | Streaming with events and a final message |
client.messages.countTokens | Exact input token counts before sending |
client.messages.batches | Half-price asynchronous processing |
client.beta.messages.toolRunner + betaZodTool | The tool loop, run for you |
mcpTools (helpers/beta/mcp) | MCP server tools in the tool runner |
client.models.list() | Models available to your key |
Common mistakes#
- Ignoring
stop_reason. Truncated and refused answers look like normal text if you only readcontent. - Reading only the first content block. Responses can contain several blocks of different types.
- Retrying 400 errors. They fail the same way every time.
- Hard-coding model names everywhere. Keep them in one config module.
Try it
Handle every stop reason
- Use
nextActionin one of your scripts and handle eachkindexplicitly. - Force
max_tokenswithmax_tokens: 20and check the truncated path. - Log
_request_idfor every call and find one request in your logs by its ID.
Check your understanding
Key takeaways
- Always branch on
stop_reason, and handle every value. - Read all content blocks, record usage and request IDs, and keep model names in one place.
- Retry 429, 5xx, and 529; fix 4xx.
- Use the SDK helpers:
parse,stream,countTokens, batches, and the tool runner.
Next steps#
Finished this article? Track it to see your progress on the roadmap.
Related articles
- Your First LLM API Call in Node.js: Request and Response AnatomyMake your first Claude API call from Node.js and TypeScript, and learn every part of the request and response: messages, system, max_tokens, stop_reason, usage.
- Tool Use (Function Calling) with Claude in TypeScriptLet the model call your functions: define tools, run the tool-use loop by hand, handle errors and parallel calls, then use the SDK tool runner with Zod-typed tools.
- LLM Cost Cheat Sheet: Prices, Formulas, and LeversA one-page reference for LLM costs: token prices at the time of writing, the cost formula with caching and batches, quick estimates, and the levers that cut a bill.