← Blog

Claude API TypeScript SDK: A Quickstart Guide

2026-09-28 · 5 min read · SubToAPI Team

If you're building a TypeScript application and want to call Claude, the fastest path is Anthropic's official @anthropic-ai/sdk package. It gives you typed request and response objects, built-in streaming support, and retry handling out of the box, so you don't have to hand-roll fetch calls and parse SSE chunks yourself.

This guide walks through everything you need to go from zero to a working Claude integration in TypeScript: installing the SDK, sending your first message, streaming tokens, using tools, and handling errors correctly. It assumes basic familiarity with Node.js and npm, but no prior experience with the Claude API.

Prerequisites

You'll need:

Installing the SDK

npm install @anthropic-ai/sdk

The package ships with its own type definitions, so there's nothing extra to install for TypeScript support.

Setting up the client

Store your key in an environment variable rather than hardcoding it:

export ANTHROPIC_API_KEY="sk-ant-..."
import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic({
  apiKey: process.env.ANTHROPIC_API_KEY,
});

The client picks up ANTHROPIC_API_KEY automatically if you don't pass it explicitly, which is convenient for local development and CI.

Sending your first message

The core method is messages.create. It takes a model name, a max_tokens limit, and an array of messages:

async function ask(question: string) {
  const response = await client.messages.create({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: question }],
  });

  const textBlock = response.content.find((b) => b.type === "text");
  console.log(textBlock?.text);
}

ask("Explain the difference between let and const in TypeScript.");

The response's content field is an array of typed blocks (text, tool_use, etc.), which is where TypeScript's typing actually pays off — your editor will autocomplete the correct fields once you narrow the block type.

Streaming responses

For chat interfaces or anything user-facing, streaming avoids the "wait for the whole answer" delay. The SDK exposes a .stream() helper that returns an async iterable:

async function askStreaming(question: string) {
  const stream = client.messages.stream({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: question }],
  });

  for await (const event of stream) {
    if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
      process.stdout.write(event.delta.text);
    }
  }

  const finalMessage = await stream.finalMessage();
  console.log("\n---\nTotal tokens:", finalMessage.usage.output_tokens);
}

finalMessage() resolves once the stream ends and gives you the complete assembled message, including usage data — useful for logging cost per request.

Using tools (function calling)

Tool use lets Claude call functions you define, which is common for building agents or structured-output pipelines:

const tools = [
  {
    name: "get_weather",
    description: "Get current weather for a city",
    input_schema: {
      type: "object" as const,
      properties: {
        city: { type: "string" },
      },
      required: ["city"],
    },
  },
];

const response = await client.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 1024,
  tools,
  messages: [{ role: "user", content: "What's the weather in Lisbon?" }],
});

const toolUse = response.content.find((b) => b.type === "tool_use");
if (toolUse) {
  console.log(toolUse.name, toolUse.input);
}

You'd then run get_weather, and send the result back in a follow-up message with a tool_result block. The TypeScript types enforce the shape of input_schema, which catches malformed tool definitions before you ever hit the network.

Handling errors

The SDK throws typed errors you can catch and branch on:

import { APIError, RateLimitError } from "@anthropic-ai/sdk";

try {
  await client.messages.create({ /* ... */ });
} catch (err) {
  if (err instanceof RateLimitError) {
    console.warn("Rate limited, retrying after backoff");
  } else if (err instanceof APIError) {
    console.error("API error:", err.status, err.message);
  } else {
    throw err;
  }
}

The SDK also retries transient failures (like 429s and 5xxs) automatically by default, with configurable retry counts via the maxRetries client option.

When you need this behind your own API

The SDK is great for calling Claude directly from a backend service you control. But if you're shipping a product where multiple team members, environments, or client apps need access — and you want per-app keys, usage tracking, and rate limits without building that infrastructure yourself — it's often faster to put a thin API layer in front.

That's what SubToAPI does: it turns your existing Claude access into a standard HTTPS API with its own sub_live_... application keys, so different services in your stack can call Claude without sharing a single raw credential. The request shape mirrors the official Messages API closely enough that switching a TypeScript client over is usually a one-line base URL change:

const response = await fetch("https://api.subtoapi.app/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SUBTOAPI_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "claude-sonnet-4-5",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Summarize this in one sentence." }],
  }),
});

Streaming, tool use, and usage metadata work the same way — see the quickstart, messages, and streaming docs for the exact request formats, or check pricing if you're evaluating it for a team.

Wrapping up

For a straightforward TypeScript integration, the official SDK covers everything: typed messages, streaming, tool use, and automatic retries. The main decision point is whether you're calling Claude from a single backend service (SDK is fine as-is) or need to distribute access across multiple apps or team members with separate keys and usage visibility (worth adding an API layer). Either way, the code you write day-to-day looks almost identical.

Questions

Does the Claude TypeScript SDK support streaming out of the box? Yes. Use client.messages.stream(), which returns an async iterable of events, and call .finalMessage() to get the complete assembled response with usage stats once streaming finishes.

Do I need to install separate type definitions for TypeScript? No. @anthropic-ai/sdk ships its own TypeScript types, so npm install @anthropic-ai/sdk is the only step needed — no @types/ package required.

Can I use the SDK with a proxy or third-party API layer instead of Anthropic directly? Yes, as long as the service exposes a compatible endpoint. You typically just point requests at a different base URL and swap the API key, as shown with SubToAPI above.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →