How to Build a Claude Bot: A Developer's Guide
What "How to Claude Bot" Usually Means
Most developers searching this phrase aren't asking how to use Claude's chat interface — they're asking how to build a bot that runs on Claude, whether that's a Discord bot, a Slack assistant, a Telegram helper, or a custom internal tool. This guide walks through the actual steps: getting API access, handling messages, managing conversation state, and deploying the bot somewhere people can use it.
The short version: a Claude bot is just a program that receives a message from a user (via Discord, Slack, a webhook, or your own frontend), sends that message to Claude's API along with conversation history, and returns Claude's response. Everything else — memory, tool use, formatting — is built around that core loop.
Step 1: Get API Access
You need a way to call Claude programmatically. There are two routes:
- Direct API access from Anthropic, which requires its own billing setup and API key management separate from your Claude.ai subscription.
- A proxy service like SubToAPI, which turns your existing Claude access into a standard HTTPS API with an
sub_live_...key. This is useful if you already pay for Claude and don't want to set up separate API billing just to prototype a bot.
Either way, you end up with a key and an endpoint you can call from your bot's backend. With SubToAPI, requests look like this:
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": 500,
"messages": [
{"role": "user", "content": "Summarize this ticket in one sentence."}
]
}'
Check the quickstart and messages docs for the full request/response shape.
Step 2: Choose Your Bot Platform
The platform determines how messages arrive and how you send replies back.
- Discord: Use
discord.jsordiscord.py, listen formessageCreateevents, and reply in the same channel or thread. - Slack: Use the Bolt SDK, subscribe to
app_mentionormessageevents, respond via the Slack Web API. - Telegram: Use
node-telegram-bot-apior the Telegram Bot API directly with long polling or webhooks. - Custom web widget: Build a small chat UI that POSTs to your backend, which then calls Claude.
The Claude-calling logic is identical across all of them — only the message-in/message-out wiring changes.
Step 3: Write the Core Message Loop
A minimal bot needs three things: a system prompt, a way to store recent conversation turns per user or channel, and a call to the API.
const conversations = new Map(); // channelId -> messages[]
async function askClaude(channelId, userText) {
const history = conversations.get(channelId) || [];
history.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: 800,
system: "You are a concise, helpful support bot for our Discord server.",
messages: history,
}),
});
const data = await res.json();
const reply = data.content[0].text;
history.push({ role: "assistant", content: reply });
conversations.set(channelId, history.slice(-20)); // keep last ~20 turns
return reply;
}
Trim history regularly — unbounded conversation arrays will eventually blow past context limits and slow every request down.
Step 4: Add Streaming for Better UX
Bots that wait 5–10 seconds before replying feel sluggish, especially in Discord or a web widget. Streaming lets you edit a message incrementally as tokens arrive instead of waiting for the full response.
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: 800,
stream: true,
messages: history,
}),
});
You then read the response as a stream of server-sent events and append text chunks to the message as they come in. See streaming docs for the event format.
Step 5: Give the Bot Tools (Optional)
If the bot needs to do more than talk — look up a ticket, check a database, call an internal API — use tool use. You define a tool schema, Claude decides when to call it, your bot executes the actual function, and sends the result back for Claude to finish the reply.
{
"tools": [
{
"name": "lookup_order",
"description": "Look up an order by ID",
"input_schema": {
"type": "object",
"properties": { "order_id": { "type": "string" } },
"required": ["order_id"]
}
}
]
}
This is how you build bots that answer "where's my order #4821" instead of just chatting. Full details in the tools guide.
Step 6: Deploy and Handle Rate Limits
Run the bot on a small always-on server (a $5 VPS, a Fly.io app, or a Render worker) since Discord and Slack bots need persistent connections or webhook endpoints. Add basic retry logic for rate limit responses, and log token usage per user if you're running the bot for a team — costs scale with message volume and context length.
If you're managing this for multiple team members, look at usage metadata per key so you can see which channels or users are driving cost. SubToAPI's pricing includes per-seat plans (Solo €9, Team €19/seat, Scale €49/seat) with a free trial at signup, which is worth it once more than one person is building or maintaining the bot.
Common Mistakes to Avoid
- Not trimming conversation history — leads to slow, expensive requests over time.
- No system prompt — the bot drifts into generic chatbot behavior instead of its intended role.
- Ignoring rate limits — a busy Discord server can trigger bursts of requests; add basic queuing.
- Skipping error handling — API timeouts and malformed responses will happen; fail gracefully with a fallback message.
Questions
Do I need Anthropic's direct API to build a Claude bot? No. You can use direct API access or a proxy service like SubToAPI, which exposes your existing Claude access as a standard HTTPS API with its own key.
Which platform is easiest to start with — Discord, Slack, or Telegram? Discord is usually the fastest to prototype on since discord.js has minimal setup and a permissive local development flow.
How do I keep the bot from forgetting context mid-conversation? Store recent messages per channel or user and send them with every request, trimming older turns once you approach the model's context limit.