← Blog

How to Build a Claude Chatbot: A Step-by-Step Guide

2026-10-13 · 5 min read · SubToAPI Team

Building a Claude chatbot means connecting a frontend chat interface to Claude's language model through an API, managing conversation state, and handling responses in a way that feels fast and natural to users. You don't need a machine learning background — you need an API key, a server to hold your logic, and a clear idea of how messages flow back and forth.

This guide walks through the full process: choosing an architecture, writing the request/response loop, adding memory and streaming, and deploying something that actually works in production.

What You Actually Need to Build

A Claude chatbot has four moving parts:

  1. A client interface — web page, mobile app, Slack bot, or CLI.
  2. A backend that stores conversation history and calls the Claude API.
  3. An API connection — either direct access to Anthropic's API or a gateway like SubToAPI that wraps your existing Claude access in a standard HTTPS API.
  4. A system prompt that defines the bot's personality, constraints, and knowledge boundaries.

The backend is the part most tutorials skip over, but it's where the real work happens: deciding how much history to send, when to stream, and how to handle errors without breaking the user's session.

Step 1: Set Up API Access

Every request to Claude needs an API key and a defined model. If you're using SubToAPI, you generate a key from the dashboard after signing up at /signup, then send requests to a single consistent endpoint regardless of which underlying model version you're calling.

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-3-5-sonnet",
    "max_tokens": 1024,
    "messages": [
      {"role": "user", "content": "Hello, who are you?"}
    ]
  }'

This single call is the core of your chatbot. Everything else — memory, UI, streaming — is built around repeating this pattern on every user turn. Full request/response details are in the /docs/messages reference.

Step 2: Design the Conversation Loop

Claude's API is stateless: it doesn't remember previous turns unless you send them. Your backend needs to maintain the message array and append to it on every exchange.

let history = [
  { role: "user", content: "I'm planning a trip to Lisbon." }
];

async function sendTurn(userMessage) {
  history.push({ role: "user", content: userMessage });

  const res = 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-3-5-sonnet",
      max_tokens: 1024,
      messages: history
    })
  });

  const data = await res.json();
  const reply = data.content[0].text;
  history.push({ role: "assistant", content: reply });
  return reply;
}

In production, store history per user session in a database, not in memory. Trim or summarize old turns once the conversation grows long — sending the entire history on every call gets expensive and eventually hits context limits.

Step 3: Add a System Prompt

A chatbot without a system prompt will drift in tone and scope. Define it once and send it on every request:

{
  "system": "You are a support assistant for a SaaS billing product. Answer only questions about invoices, plans, and payments. If asked anything else, redirect politely.",
  "model": "claude-3-5-sonnet",
  "messages": [...]
}

Keep the system prompt specific. Vague instructions like "be helpful" produce inconsistent behavior; explicit scope, tone, and refusal rules produce a bot that behaves the same way across thousands of conversations.

Step 4: Stream Responses

Users notice latency immediately in chat interfaces. Waiting for a full response before showing anything feels broken, even if the total time is reasonable. Streaming fixes this by rendering tokens as they're generated.

const res = 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-3-5-sonnet",
    max_tokens: 1024,
    stream: true,
    messages: history
  })
});

const reader = res.body.getReader();
const decoder = new TextDecoder();

while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  const chunk = decoder.decode(value);
  // parse SSE chunk and append text to the UI
}

Setting up server-sent events correctly is one of the more fiddly parts of a chatbot build — see /docs/streaming for the exact event format and parsing example.

Step 5: Give It Tools (Optional but Powerful)

A chatbot limited to generating text can't check order status, look up a database record, or fetch live data. Tool use lets Claude call functions you define, get the result, and incorporate it into its answer.

{
  "tools": [
    {
      "name": "get_order_status",
      "description": "Look up the status of an order by ID",
      "input_schema": {
        "type": "object",
        "properties": { "order_id": { "type": "string" } },
        "required": ["order_id"]
      }
    }
  ]
}

When Claude decides it needs that data, it returns a tool call instead of plain text; your backend executes the function and sends the result back in the next message. This is what turns a chatbot into an actual assistant. Details and worked examples are at /docs/tools.

Step 6: Deploy and Monitor

Once the loop works locally, deploy the backend behind your existing app server or a lightweight API route. Watch for three things in production:

If you're running multiple apps or team members against Claude, a unified API key setup saves a lot of operational overhead compared to juggling raw provider credentials across projects — see /pricing for how plans scale with usage and seats.

Getting Started Quickly

If you want to skip the account and billing setup and go straight to a working call, the /docs/quickstart guide covers key generation and your first request end to end, with the same request format used throughout this article.

questions

Do I need to fine-tune Claude to build a chatbot? No. Almost all chatbot behavior — tone, scope, knowledge boundaries — comes from the system prompt and the context you send, not from fine-tuning. Fine-tuning is rarely necessary or available for most use cases.

How much conversation history should I send on each request? Send enough to maintain context, usually the last 10–20 turns, and summarize or drop older messages once you approach your token budget. Sending the full history indefinitely increases cost and risks hitting context limits.

What's the difference between calling Claude directly and using a gateway like SubToAPI? Direct access means managing provider-specific SDKs, keys, and version changes yourself. A gateway gives you one stable endpoint, application-level API keys, and usage visibility across a team, which matters once you have more than one chatbot or developer in the mix.

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 →