← Blog

Claude API SDK for TypeScript Projects: Setup Guide

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

If you're building a TypeScript project and need to call Claude, you have two practical routes: install Anthropic's official @anthropic-ai/sdk package, or use an HTTPS API that fronts your Claude access with the same request shape. Either way, the goal is the same — a typed client, predictable streaming, and tool calling that doesn't fight your compiler.

This article walks through setting up a Claude client in TypeScript, handling types for messages and tool use, streaming responses into a frontend, and where a service like SubToAPI fits if you want application-level API keys instead of managing Claude credentials directly inside your app.

Installing the SDK

The official SDK gives you typed request and response objects out of the box:

npm install @anthropic-ai/sdk
import Anthropic from "@anthropic-ai/sdk";

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

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

  return message.content;
}

TypeScript picks up the response shape automatically — message.content is typed as an array of content blocks, so autocomplete works for text, tool_use, and other block types without you writing manual interfaces.

Typing your own request builders

Most real projects wrap the raw client in a function that takes your app's own types and converts them to Claude's message format. This is where TypeScript actually earns its keep:

interface ChatTurn {
  role: "user" | "assistant";
  text: string;
}

function toClaudeMessages(turns: ChatTurn[]) {
  return turns.map((t) => ({
    role: t.role,
    content: t.text,
  }));
}

Keeping a thin translation layer between your domain types and the API's message format means you can swap providers or endpoints later without touching your business logic.

Streaming in TypeScript

Streaming is where a lot of TypeScript setups get messy, because you're juggling async iterables and partial JSON. The SDK exposes a stream helper that handles this cleanly:

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

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

If you're piping this to a browser, wrap it in a ReadableStream or use Server-Sent Events from your API route. Next.js route handlers and Node's built-in http module both support this without extra dependencies.

Tool use with typed schemas

Defining tools in TypeScript benefits from keeping your JSON schema and your runtime validation in sync. A common pattern is defining the tool once and deriving types from it, or using a schema library like zod alongside the raw JSON schema Claude expects:

const weatherTool = {
  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-20250514",
  max_tokens: 1024,
  tools: [weatherTool],
  messages: [{ role: "user", content: "What's the weather in Lisbon?" }],
});

The response will include a tool_use content block when Claude decides to call it. Check content_block.type === "tool_use" before accessing input, since TypeScript won't let you access tool-specific fields on a plain text block without narrowing first.

Where SubToAPI fits

The official SDK talks directly to Anthropic's API using an Anthropic API key. If you're building a product on top of Claude and want to issue separate keys per application, environment, or customer without creating new Anthropic accounts, SubToAPI sits in front of your existing Claude access and exposes the same kind of HTTPS interface.

You get sub_live_... keys scoped per app, the same streaming and tool-use behavior, and usage metadata per key — useful if you're shipping a TypeScript backend for multiple clients or internal services and don't want to manage a pile of raw provider credentials.

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-20250514",
    max_tokens: 1024,
    messages: [{ role: "user", content: "Summarize this changelog." }],
  }),
});

const data = await response.json();

Since the request and response shapes mirror the standard Messages API, you can reuse your existing TypeScript types and streaming handlers — the change is mostly in your auth header and base URL. Setup takes a few minutes via /signup, and the /docs/quickstart covers the exact request format, with /docs/messages, /docs/streaming, and /docs/tools breaking down each feature. Plans start at €9/month for solo use, with team seats on the €19 and €49 tiers detailed on /pricing.

Error handling patterns

Wrap calls in a typed error handler so failures don't leak any into your codebase:

try {
  const message = await client.messages.create({ /* ... */ });
} catch (err) {
  if (err instanceof Anthropic.APIError) {
    console.error(err.status, err.message);
  } else {
    throw err;
  }
}

This keeps your catch blocks specific and avoids silently swallowing unrelated bugs as "API errors."

Choosing project structure

For anything beyond a script, separate three layers: a low-level client wrapper, a typed message builder, and your application logic. This keeps model names, token limits, and tool schemas in one place, so upgrading models or switching between direct Anthropic access and a proxy like SubToAPI is a config change, not a rewrite.

questions

Does the official Anthropic SDK support TypeScript natively? Yes. @anthropic-ai/sdk ships with full TypeScript types for requests, responses, and streaming events, so you get autocomplete and compile-time checks without extra type packages.

Can I use fetch directly instead of the SDK? Yes, both the official API and SubToAPI accept plain HTTPS requests, so fetch or axios work fine if you want to avoid the extra dependency — you just lose the built-in streaming helpers.

How do I handle streaming responses in a Next.js API route? Use the SDK's stream() method or a raw fetch with response.body as a ReadableStream, then forward chunks to the client via a ReadableStream response or Server-Sent Events — this works the same whether you're calling Anthropic directly or through SubToAPI's /v1/messages endpoint.

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 →