← Blog

Claude API Telegram Bot Integration Guide

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

Building a Telegram bot powered by Claude means connecting two pieces: Telegram's Bot API (which handles messages, chats, and updates) and Claude's API (which generates the responses). This guide walks through both sides — registering a bot, setting up a webhook or polling loop, calling Claude with the user's message, and sending the reply back — so you have a working integration by the end.

If you're searching for how to wire these two APIs together, the short answer is: your server receives a Telegram update, extracts the text, sends it to Claude's messages endpoint, and posts the response back via Telegram's sendMessage call. Everything below fills in the details, including the parts people usually get wrong — handling streaming, managing conversation history per chat, and avoiding Telegram's timeout limits.

What you need before starting

Step 1: Register and configure the bot

After creating the bot with BotFather, save the token. You'll use it to call Telegram's Bot API at:

https://api.telegram.org/bot<YOUR_TOKEN>/

Decide between webhooks (Telegram pushes updates to your server) and polling (your server pulls updates on an interval). Webhooks are better for production — lower latency, no wasted requests — but require a public HTTPS URL. Polling is simpler for local testing.

To set a webhook:

curl -X POST "https://api.telegram.org/bot<YOUR_TOKEN>/setWebhook" \
  -d "url=https://yourdomain.com/telegram/webhook"

Step 2: Receive and parse incoming messages

Telegram sends a JSON payload to your webhook for every update. The relevant fields are usually message.chat.id and message.text:

app.post('/telegram/webhook', async (req, res) => {
  const update = req.body;
  const chatId = update.message?.chat?.id;
  const text = update.message?.text;

  if (!chatId || !text) {
    return res.sendStatus(200);
  }

  const reply = await askClaude(chatId, text);
  await sendTelegramMessage(chatId, reply);
  res.sendStatus(200);
});

Always return a 200 quickly — Telegram will retry if your webhook doesn't respond within a few seconds, which can cause duplicate messages if Claude's response takes a while to generate.

Step 3: Call Claude for a response

This is where you send the user's message to Claude and get text back. Using SubToAPI, the request looks like a standard HTTP call with your sub_live_... key:

async function askClaude(chatId, text) {
  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: 1024,
      messages: conversationHistory[chatId] || [{ role: 'user', content: text }]
    })
  });

  const data = await res.json();
  return data.content[0].text;
}

Because Telegram bots are typically consumer-facing and used across teams or multiple users, routing requests through SubToAPI means you get one API key per application, usage metadata per request, and the ability to add team members on your dashboard without sharing raw provider credentials. See the quickstart and messages endpoint docs for the full request format.

Step 4: Send the reply back to Telegram

async function sendTelegramMessage(chatId, text) {
  await fetch(`https://api.telegram.org/bot<YOUR_TOKEN>/sendMessage`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ chat_id: chatId, text })
  });
}

Telegram messages have a 4096-character limit. If Claude's response is longer, split it into chunks before sending, or instruct Claude in your system prompt to keep answers concise for chat.

Managing conversation history per chat

Telegram bots are stateless by default — each webhook call is independent. To hold a real conversation, you need to store message history keyed by chat.id, typically in Redis or a database:

conversationHistory[chatId] = conversationHistory[chatId] || [];
conversationHistory[chatId].push({ role: 'user', content: text });
// after getting Claude's reply:
conversationHistory[chatId].push({ role: 'assistant', content: reply });

Trim old messages periodically to control token usage and cost — Claude charges per token, and long-running chats can grow expensive fast without a cap.

Handling streaming responses

Telegram doesn't support token-by-token streaming the way a web chat UI does, but you can simulate progressive updates by editing the sent message as new chunks arrive, using editMessageText. This is more complex and usually unnecessary for a bot — most Telegram bot users are fine waiting a few seconds for a complete reply. If you do want streaming for a web-based companion interface, see the streaming docs.

Adding tool use for richer bots

If your bot needs to look up data, call external APIs, or perform actions (checking order status, searching a database), Claude's tool use feature lets you define functions the model can call mid-conversation. The model returns a tool call, your bot executes it, and you feed the result back in a follow-up message. Details are in the tools documentation.

Deployment checklist

A production-ready version adds error handling for Telegram API failures, retries for Claude timeouts, and a fallback message when something breaks. Start simple, get the loop working end-to-end, then layer in robustness.

Questions

Do I need Anthropic's official SDK to build this? No. Any HTTP client works since both Telegram's Bot API and Claude's API are plain REST endpoints. The SDK just saves boilerplate.

Can one bot serve multiple Telegram users without mixing up conversations? Yes, as long as you key conversation history by chat.id and don't share a single history array across all users.

Is a webhook or polling better for a Claude-powered bot? Webhooks for production — they're lower latency and don't poll Telegram's servers constantly. Use polling only for local development where you don't have a public HTTPS endpoint yet.

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 →