Claude API Integration with Node.js: A Full Guide
Integrating Claude into a Node.js application means setting up authenticated HTTPS requests to an API endpoint, sending structured message payloads, and handling responses (streamed or not) in your app logic. This guide walks through the full process: installing dependencies, authenticating, sending your first request, handling errors, and structuring your code for production use.
There are two practical paths here. You can call Anthropic's Claude API directly with your own account and manage keys, rate limits, and billing yourself, or you can go through a proxy like SubToAPI that turns your existing Claude access into a standard HTTPS API with app-specific keys. The integration pattern in Node.js is nearly identical either way — you're sending JSON payloads over HTTPS and parsing JSON or streamed responses back.
What You Need Before You Start
- Node.js 18+ (native
fetchsupport, no extra HTTP client required) - An API key (either from Anthropic directly or a
sub_live_...key from SubToAPI) - A basic understanding of async/await in JavaScript
You don't strictly need an SDK. Claude's API is plain HTTPS with JSON bodies, so fetch, axios, or node-fetch all work fine. This makes it easy to integrate into existing Express, Fastify, Next.js, or serverless functions without adding heavy dependencies.
Step 1: Set Up Your Environment
Store your API key in an environment variable, never in source code:
# .env
SUBTOAPI_KEY=sub_live_xxxxxxxxxxxxxxxx
Load it with dotenv or your framework's built-in env handling:
import 'dotenv/config';
const API_KEY = process.env.SUBTOAPI_KEY;
if (!API_KEY) {
throw new Error('Missing SUBTOAPI_KEY environment variable');
}
Step 2: Send Your First Request
A minimal Node.js integration using native fetch:
async function askClaude(prompt) {
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: prompt },
],
}),
});
if (!response.ok) {
const errorBody = await response.text();
throw new Error(`Request failed (${response.status}): ${errorBody}`);
}
const data = await response.json();
return data.content[0].text;
}
const answer = await askClaude('Explain event loops in one paragraph.');
console.log(answer);
This pattern — build headers, POST a JSON body, parse the response — is the backbone of nearly every Claude integration in Node.js, regardless of framework. Full request/response details are in the docs.
Step 3: Wrap It in a Reusable Client
For anything beyond a script, wrap the call in a small module so the rest of your codebase doesn't deal with raw fetch logic:
// claudeClient.js
const BASE_URL = 'https://api.subtoapi.app/v1';
export async function sendMessage({ messages, model = 'claude-sonnet-4-5', maxTokens = 1024 }) {
const res = await fetch(`${BASE_URL}/messages`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SUBTOAPI_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model,
max_tokens: maxTokens,
messages,
}),
});
if (!res.ok) {
throw new Error(`Claude API error ${res.status}: ${await res.text()}`);
}
return res.json();
}
Now every route or service in your app imports sendMessage instead of duplicating fetch logic. This also gives you a single place to add retries, logging, or usage tracking.
Step 4: Handle Multi-Turn Conversations
Claude's API is stateless — you send the full conversation history with each request. In Node.js, this usually means keeping an array of messages in memory (for a script) or in a session/database (for a web app):
const conversation = [
{ role: 'user', content: 'What is a closure in JavaScript?' },
];
const first = await sendMessage({ messages: conversation });
conversation.push({ role: 'assistant', content: first.content[0].text });
conversation.push({ role: 'user', content: 'Give me a short code example.' });
const second = await sendMessage({ messages: conversation });
If you're building a chat UI, this array typically lives in your frontend state or backend session store, and gets sent in full with every new user message.
Step 5: Add Error Handling and Retries
Production integrations need to handle rate limits, timeouts, and transient failures gracefully:
async function sendWithRetry(payload, attempts = 3) {
for (let i = 0; i < attempts; i++) {
try {
return await sendMessage(payload);
} catch (err) {
if (i === attempts - 1) throw err;
await new Promise((r) => setTimeout(r, 500 * (i + 1)));
}
}
}
Distinguish between retryable errors (429, 5xx) and non-retryable ones (400, 401) so you don't waste time retrying a bad request or invalid key.
Where SubToAPI Fits In
If you already have Claude access through your subscription but want a stable HTTPS API for your Node.js app — with app-specific keys, streaming support, tool use, and usage metadata per key — SubToAPI sits between your app and Claude without changing this integration pattern. You get a sub_live_... key, point your fetch calls at https://api.subtoapi.app/v1/messages, and the rest of your Node.js code stays exactly as shown above. Plans start at €9/month on the Solo tier, with Team and Scale tiers for multi-key setups — see /pricing for details, or check the quickstart to get a key in a few minutes.
For streaming responses in Node.js specifically — useful for chat UIs where you want tokens to appear as they're generated — see the streaming docs at /docs/streaming.
Questions
Do I need Anthropic's official SDK to integrate Claude in Node.js? No. Node.js 18+ has native fetch, which is enough to send requests and parse JSON responses. An SDK can reduce boilerplate, but plain HTTP works fine for most integrations.
How do I keep conversation history across multiple requests? Claude's API is stateless, so you maintain an array of { role, content } messages in your app (memory, session, or database) and send the full history with each new request.
What's the fastest way to test a Claude integration without full Anthropic setup? Sign up at /signup for a SubToAPI key, then follow the quickstart — you can send your first curl or Node.js request in under five minutes.