Create a Simple Chatbot Using Claude in 20 Minutes
Creating a simple chatbot using Claude comes down to three things: an API key, a loop that sends user messages and appends Claude's replies, and somewhere to run that loop (a terminal script, a web backend, or a Slack bot). You don't need a framework, a vector database, or an agent library to get a working chatbot — a few dozen lines of code are enough to start, and you can add complexity later only if you actually need it.
This guide walks through the minimum viable chatbot: getting access, making the first API call, keeping conversation history so Claude remembers context, and the two realistic paths for getting an API key (direct Anthropic access vs. a wrapper like SubToAPI that turns your existing Claude subscription into an API).
What you actually need
- An API key that can call Claude's messages endpoint
- A runtime — Node.js, Python, or even a shell script with curl
- A loop that stores the conversation as an array of
{role, content}objects - A place to send it: CLI, a small web server, or a chat widget
That's it. Everything else — tool calling, streaming, file uploads — is optional for a "simple" chatbot.
Step 1: Get an API key
You have two practical options:
- Anthropic's own API — requires a separate developer account and billing, priced per token, best if you're building something that needs to scale independently of your personal Claude usage.
- SubToAPI — turns your existing Claude access into an HTTPS API with a
sub_live_...key you generate from a dashboard. Useful if you already have a Claude subscription and want to start building without setting up separate API billing. Sign up at /signup, grab a key, and check /pricing for the Solo, Team, and Scale plans.
Either way, the request shape is the same: you POST a messages array to an endpoint and get a text reply back.
Step 2: Make your first call
Here's the minimal request using SubToAPI's endpoint, which mirrors the standard Claude messages format:
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5",
"max_tokens": 512,
"messages": [
{ "role": "user", "content": "Say hello in one short sentence." }
]
}'
You'll get back a JSON object with a content array containing Claude's reply. Full request/response details are in /docs/messages, and /docs/quickstart walks through the whole setup if this is your first API call.
Step 3: Build the conversation loop
A chatbot isn't just one request — it needs to remember what was said before. The pattern is simple: keep an array of messages, append the user's input, send the whole array, append Claude's reply, repeat.
import readline from "node:readline/promises";
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
const messages = [];
async function ask(userText) {
messages.push({ role: "user", content: userText });
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-sonnet-4-5",
max_tokens: 512,
messages,
}),
});
const data = await res.json();
const reply = data.content[0].text;
messages.push({ role: "assistant", content: reply });
return reply;
}
while (true) {
const input = await rl.question("You: ");
if (input === "exit") break;
const reply = await ask(input);
console.log("Claude:", reply);
}
This is a fully functional command-line chatbot. Run it, type a question, get a reply, ask a follow-up — Claude will remember what you said earlier because you're resending the full history each time.
Step 4: Add a system prompt
To give your chatbot a personality or purpose (support agent, coding tutor, recipe assistant), add a system field to the request:
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 512,
system: "You are a concise, friendly assistant for a cooking app. Keep answers under 3 sentences.",
messages,
}),
This single field does more for chatbot quality than almost anything else — it's the first thing to tune once the basic loop works.
Step 5: Stream responses (optional but recommended)
For a web or chat-widget interface, streaming makes the bot feel responsive instead of making users wait for the full reply. Set "stream": true in the request and read the server-sent events as they arrive — see /docs/streaming for the exact event format and a working example.
Step 6: Move it from terminal to a real interface
Once the loop works in a script, wrapping it in a small Express or Flask endpoint turns it into a chatbot your frontend can call:
app.post("/chat", async (req, res) => {
const { message, history } = req.body;
history.push({ role: "user", content: message });
const apiRes = 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: 512, messages: history }),
});
const data = await apiRes.json();
res.json({ reply: data.content[0].text });
});
Your frontend keeps the history array in state (or a session store) and posts it with each new message. That's the entire backend for a working chatbot — no database required unless you want persistent history across sessions.
When to add tools
If your chatbot needs to look things up (check order status, search a knowledge base, hit an internal API) rather than just chat, you'll want Claude's tool-use feature: you define a function schema, Claude decides when to call it, and you execute the actual logic. That's a separate step from a "simple" chatbot but it's a natural next move once the basic loop is working — see /docs/tools for the request format.
Questions
Do I need the official Anthropic API to build a Claude chatbot? No. You can use the official API directly, or use a service like SubToAPI that exposes your existing Claude access as an API key, which skips setting up separate developer billing.
How much conversation history should I send with each message? Send the full running history for short chatbots. For longer conversations, trim or summarize older turns once you approach the model's context limit, since every request resends the entire array.
Can I build this without a backend server? For local testing, yes — a terminal script works fine. For anything user-facing, keep the API key server-side and proxy requests through your own backend so the key isn't exposed in browser code.