Connect Claude to Telegram Business — supervised AI replies
A working architecture for routing your Telegram Business inbox through Claude, with the user kept firmly in the loop. Code, prompts, costs, and what to do when Claude is wrong.
The killer feature of Telegram Business in 2026 isn’t the opening hours widget or the away message. It’s the bot you connect to your personal account — and the moment that bot starts drafting good replies, you’re running a one-person operation that scales like a five-person team.
This guide builds that bot, properly. Claude as the brain. You as the editor. No auto-send.
What you’ll build
A bot connected to your Business account that:
- Watches every incoming message to your account.
- Asks Claude to draft a reply in your voice.
- Posts the draft into a private channel you control (“Drafts”).
- Lets you tap Send or Edit in that channel; the bot then sends from your account.
Claude never speaks directly. You always sign off.
Architecture
[Customer DM] → [Your Telegram account] → [Telegram Business webhook]
↓
[Your bot server]
↓ ↓
[Claude API] [Conversation history DB]
↓
[Drafts channel] ← you approve
↓
[Bot sends as you] → [Customer]
Three components: a webhook, an LLM call with context, and an approval loop. We’ll build each in turn.
Provision the bot and connect it to your account
- Create a bot via @BotFather (
/newbot). - In Telegram, Settings → Telegram Business → Chatbots. Paste your bot’s
@username. Grant Read incoming messages + Reply on your behalf. - In your bot code, listen for
business_connectionupdates to know when you’ve been connected, and store the resultingbusiness_connection_id— you’ll need it on every outgoing reply.
// pseudo-code; pick your favorite framework
bot.on("business_connection", async (update) => {
await db.businessConnection.upsert({
where: { userId: update.user.id },
update: { id: update.id, can_reply: update.can_reply },
create: { id: update.id, userId: update.user.id, can_reply: update.can_reply },
});
}); core.telegram.org Business Connection reference ↗ Capture incoming messages
Telegram sends a business_message update when someone DMs your account. The shape is identical to a regular message, with an extra business_connection_id.
bot.on("business_message", async (update) => {
const msg = update.business_message;
await db.message.create({
data: {
direction: "in",
chatId: msg.chat.id,
fromUserId: msg.from.id,
text: msg.text,
receivedAt: new Date(msg.date * 1000),
businessConnectionId: update.business_connection_id,
},
});
await draftReply(msg);
});The chat.id is the customer’s user id. Storing the conversation thread keyed on it is the simplest model.
Build the prompt
Claude needs three things to draft well: who you are, what you’ve already said, and what just came in.
async function draftReply(incomingMsg) {
const history = await db.message.findMany({
where: { chatId: incomingMsg.chat.id },
orderBy: { receivedAt: "desc" },
take: 20,
});
const conversation = history.reverse().map((m) => ({
role: m.direction === "in" ? "user" : "assistant",
content: m.text,
}));
const draft = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 600,
system: SYSTEM_PROMPT,
messages: [
...conversation,
{ role: "user", content: incomingMsg.text },
],
});
return draft.content[0].text;
}The system prompt is where most of the work happens. Keep it short, specific, and firmly in your voice:
You draft Telegram DM replies on behalf of {your_name}, a {your_role}.
Voice: warm, concise, never gushing. Lowercase i for "I" only when the
human you're replying to does first.
Rules:
- Reply in the same language as the incoming message.
- If the message asks for a price, link them to /pricing rather than
quoting (the human will adjust).
- Never promise calendar times. Suggest "later this week" and let
the human commit.
- If the message is unclear, ask one clarifying question.
- If the message is hostile or spammy, draft a polite one-liner
closing the thread.
- Maximum 4 sentences unless the user asks for detail.Iterate on this prompt for two weeks. It’s the difference between drafts you ship 90% of the time vs 30%.
Post the draft for approval
Create a private channel in your account (“Drafts”). Add your bot as admin. Every draft posts there as a message with two inline buttons: Send and Edit.
async function postDraftForApproval(incomingMsg, draftText) {
await bot.api.sendMessage(DRAFTS_CHANNEL_ID, formatPreview(incomingMsg, draftText), {
reply_markup: {
inline_keyboard: [[
{ text: "✓ Send", callback_data: `send:${incomingMsg.chat.id}:${draftId}` },
{ text: "✎ Edit", callback_data: `edit:${incomingMsg.chat.id}:${draftId}` },
]],
},
});
}
function formatPreview(incomingMsg, draftText) {
return `*From* ${incomingMsg.from.first_name} (@${incomingMsg.from.username || "—"})
> ${incomingMsg.text}
---
*Draft:*
${draftText}`;
}The Drafts channel becomes your morning queue. Skim, tap Send on what’s right, Edit on what’s not.
Send the approved reply as you
On callback, your bot uses the stored business_connection_id to send the reply on your behalf:
bot.on("callback_query", async (cq) => {
const [action, chatId, draftId] = cq.data.split(":");
const draft = await db.draft.findUnique({ where: { id: draftId } });
const conn = await db.businessConnection.findFirst();
if (action === "send") {
await bot.api.sendMessage(Number(chatId), draft.text, {
business_connection_id: conn.id,
});
await db.message.create({
data: { direction: "out", chatId: Number(chatId), text: draft.text, sentAt: new Date() },
});
await bot.api.editMessageText(DRAFTS_CHANNEL_ID, cq.message.message_id, "✓ Sent: " + draft.text);
}
await bot.api.answerCallbackQuery(cq.id);
});business_connection_id is what tells Telegram “this message comes from the user’s account, not the bot’s.” Without it, the customer sees the reply from your bot, not from you — different relationship entirely.
Handle Edit gracefully
Tap Edit → bot sends the draft text back to the Drafts channel as a regular message with a force_reply so you can edit and reply. Your reply becomes the new draft. Tap Send on the edited version.
A two-tap flow for the common case (it’s good), three taps for the edit case (it’s not perfect, fix it).
Cost economics
Per draft, with Claude Sonnet 4.6 at current pricing:
- Input tokens: ~800 (system + 20-msg history + new message): $0.0024
- Output tokens: ~250 (the draft): $0.0038
- Per-draft cost: ~$0.006
100 drafts per day = $0.60/day = $18/month. For a one-person business this is ~30 minutes of saved typing time per day.
If you stay on Sonnet 4.6 for one year: $216. If you migrate to Haiku 4.5 for routine drafts and only invoke Sonnet on flagged messages, halve that.
What goes wrong
- Claude is too verbose. Add
Maximum 4 sentencesto system prompt. AddSentences must average under 16 words.Iterate. - Claude makes up facts about your offering. Move pricing/calendar/policy into a Quick Reply, not into Claude’s context. Have Claude link rather than quote.
- Claude can’t see attachments. Telegram delivers media + caption. Pass the caption to Claude with a note “[user sent image]”. For real image understanding, route via Claude’s vision endpoints.
- Two customers DM you the same thing simultaneously. Lock per-chat in your handler. Otherwise both drafts post to the channel at once and you’ll mis-tap.
- The Drafts channel gets noisy. Add a topic filter (“only post drafts for messages from non-contacts” or “only when conversation is older than 24 hours”) to keep volume sane.
Privacy: tell people
Your /welcome Quick Reply should disclose: “An assistant drafts my replies for me to review before sending.” Some users will appreciate the transparency. The ones who don’t were never going to convert anyway.
When to graduate to auto-send
Track approval rate per category (using Claude itself to tag messages: pricing, scheduling, support, sales, hostile, other). When a category is at >95% approval rate over 100 messages, you can flip auto-send for that category — leave a manual review trigger for outliers.
The two categories that auto-send safely first: greeting acknowledgements and link-only replies (“here’s the pricing page: …”). The two that almost never do: pricing negotiation and refunds.
Read next
Telegram Business, configured right
A complete walkthrough of every Telegram Business setting that matters — opening hours, quick replies, away messages, intro, location, and the chatbot integration that ties it together.
The Telegram glossary — every term that matters in 2026
A reference glossary of every Telegram concept, API surface, and product feature you need to know — with one-sentence definitions and direct links to the official docs.
Honest revenue benchmarks: what Telegram channels and bots actually earn in 2026
Real revenue numbers from real operators across 12 niches — from signal channels to AI bots — with audience size, ARPU, and the gotchas behind each figure.