How to build a Telegram bot
A Telegram bot is a program that runs on your own server and sends requests to api.telegram.org with a token; Telegram itself runs no code of yours. Creating the bot with BotFather takes a few minutes, and the real work starts where you decide how to receive messages and what to see inside a group.
- Lesson 5 of 8
- Beginner
- Free, no signup
From zero to a bot that answers
The first four steps take minutes. It is the fifth that defines the project.
-
1
BotFather
The newbot command, a display name and a username ending in bot.
-
2
The token
The token is the bot identity, not a key beside a password. It belongs in an environment variable.
-
3
Test with getMe
One request, before writing any code. The answer is always JSON, even when it is an error.
-
4
The first commands
start and one or two more, registered in BotFather so they appear in the suggestion list.
-
5
Hosting and staying up
The program has to come back up after a restart. Updates are not kept longer than a day.
None of these steps tells Telegram where your code should run. Hosting is yours from start to finish.
Last checked: Facts and tool names in this lesson are re-checked against their sources on this date.
What exactly is a Telegram bot and how does it work?
A Telegram bot is a special account with no person behind it, only your program. That program runs wherever you put it, on a server or even on your own laptop, and talks to Telegram over a web API. Telegram does not host your code and does not run it; it only hands you the messages and takes yours.
The way they talk is a simple pattern, and the Bot API documentation writes it exactly like this: all queries must be served over HTTPS and presented in this form: https://api.telegram.org/bot<token>/METHOD_NAME. Every method is a URL. The response is always a JSON object carrying an ok field.
The token is what the documentation calls an authentication token, and it says each bot is given a unique one when it is created; its shape is something like 123456:ABC-DEF.... That sentence carries two meanings and the second matters more: the token is not a key that comes with a password beside it, the token is the identity. Anyone holding that string is your bot.
So the overall structure is this: a user writes something in Telegram, Telegram puts it in the queue of updates for your bot, your program picks it up, decides, and sends an answer with an HTTPS request. If you have read what an API is, nothing here is new except the names of the methods.

From BotFather to the first message, step by step
Telegram itself does not create the bot; a bot called @BotFather does. You go to it in Telegram, send /newbot, give a display name and a username ending in bot, and it hands you the token. You can also register the command list there, which most tutorials leave out and which is exactly what raises the suggestion list when a user types a slash. Per the documentation, commands always start with the / symbol and are at most 32 characters.
Before writing any code, test the token. One request is enough:
curl -s "https://api.telegram.org/bot<token>/getMe"If the token is right you get the bot details in JSON. If it is wrong, what comes back is not an HTTP error page but the same JSON envelope. We tried it from our own server today with a made up token and the answer was exactly this:
{"ok":false,"error_code":401,"description":"Unauthorized"}We show that on purpose, because the whole shape of the work is in that one line: ok says whether it succeeded, and if not, description says why. Your program must always look at ok first, not only at the HTTP status code.
After that, the first thing the bot has to know is how to answer /start, because that is the button the user opens it with. Write one sentence saying what the bot does and what to press next. A bot that answers /start vaguely gets closed right there.
Should I receive messages with getUpdates or with a webhook?
The documentation is explicit: there are two ways of receiving updates and they are mutually exclusive, the getUpdates method on one hand and webhooks on the other. Which means that if a webhook is set, getUpdates does not work at all, and that one sentence explains most first night errors.
In the first mode your program keeps asking whether there is anything new. It is simple, needs no public address and runs on a laptop, so it is the right choice for learning and for a first version. One thing the documentation reminds you of: recalculate the offset after each response, or you will receive the same messages again.
In the second mode you give an address and Telegram sends an HTTPS POST request to it whenever there is something. It is more efficient and it is the right answer for a busy bot. Know two things from the documentation itself: if your address answers with anything other than a 2XX code, Telegram repeats the request and gives up after a reasonable number of attempts. And more importantly, incoming updates are stored on the Telegram server until the bot receives them, but they are not kept longer than 24 hours.
That last sentence is an operational decision for you, not a detail. It means that if the bot server stays down for a whole day, that day messages are gone and there is no way to get them back. For a hobby bot it does not matter; for a customer support bot it does, and it needs an alert.
Two ways of receiving messages, and they do not combine
Does the bot have a public HTTPS address?
getUpdates
- Runs on a laptop, with no domain and no certificate
- You have to recalculate the offset after each response
- Good enough for learning and for a first version
Webhook
- Telegram sends one HTTPS POST for each update
- A response other than 2XX makes Telegram repeat the request
- More efficient, and it needs a server that is always reachable
The documentation says the two are mutually exclusive. If a webhook is set, getUpdates does not answer at all.
What does a bot see inside a group?
This section is both the privacy question and the reason your bot "does not work" in a group. Telegram has a mode called Privacy Mode, on by default for every bot added to a group, and in that mode the bot only sees these: commands explicitly meant for it, such as /command@this_bot; general commands like /start if it was the last bot to send a message to the group; inline messages sent via the bot; and replies to messages meant for this bot.
By contrast, regardless of the mode, every bot receives these: all service messages, all messages from private chats, and all messages from channels where it is a member. There is one exception that catches a lot of people out: bots added to a group as admins always receive all messages.
The mode can be turned off, and then the bot sees every message like an ordinary user, but two points: the change does not take effect until the bot is added to the group again, and Telegram itself writes on that same page that it only recommends doing this where it is absolutely necessary for the bot to work, and that in most cases the force reply option is more than enough.
Our position is the same: leave the default on. Not only because a group member does not expect a bot to read their whole conversation, but because your bot does not want those messages either, and not processing them is both cheaper and safer. If you genuinely have to turn it off, say what the bot reads in the /start message itself. Group members can see the current privacy setting of any bot in the member list, so hiding it is not an option anyway.
What a bot sees in a group with the default mode on
-
A command explicitly for it
The command@this_bot form, meaning the user has said which bot they are talking to.
-
A general command, under one condition
Like start, but only if this bot was the last bot to send a message to the group.
-
An inline message sent via it
Something the user produced by typing the bot name inside that chat.
-
Replies to messages meant for it
This is why Telegram suggests force reply instead of turning privacy mode off.
-
The rest of the group conversation, no
And group members can see the privacy setting of any bot in the member list.
One exception: bots added as admins always receive all messages.
The limits and the mistakes everyone makes the first time
There are three families of limit and all three are written in the official FAQ. First, message rate: in a single chat, avoid sending more than one message per second; Telegram says it may allow short bursts over that but eventually you begin receiving 429 errors. In a group, a bot cannot send more than 20 messages per minute. And for bulk notifications, a bot cannot broadcast more than about 30 messages per second.
Second, paid broadcasts. If that ceiling is too low, Telegram has a feature that raises it to 1000 messages per second, where each message over the free 30 per second costs 0.1 Stars. It also writes the condition, and it is not a small one: the bot must have at least 100,000 Stars on its balance and at least 100,000 monthly active users. Which means this route is not for your new bot, and you are better off planning for a queue and a schedule than for buying speed.
Third, files. A bot can send files of up to 50 MB, and the getFile method only works with files of up to 20 MB. Those two numbers are not the same, and this is exactly where a bot that accepts video works in testing and breaks in a real user hands.
And three mistakes that keep recurring. First, putting the token inside code that gets published on GitHub; since the token is the bot identity, anyone who sees it can send messages as you. A token belongs in an environment variable, not in a source file. Second, sending messages in a loop with no spacing, which walks straight into that 429. Third, assuming the bot is always up: your program will fall over one day, and if it stays down for more than 24 hours the messages from that window do not come back.
Before you put the bot in a user hands
Check these
- The token sits in an environment variable and in no file that gets published
- The code reads the ok field of the response before anything else
- Bulk sending is spaced out and handles the 429 error
- The start message says what the bot does and what it reads
- The program comes back up by itself after a server restart
Do not do these
- Turning privacy mode off because it is easier
- Counting on paid broadcasts for a new bot
- Assuming getFile works with a large file too
- Setting a webhook and then wondering why getUpdates answers nothing
This sheet does not make the bot flawless. It stops the three mistakes that cost more to undo than to prevent.
The fast path, with AI
This is where the work genuinely gets fast. Writing your first bot from a plain description of what it should do is something models do well today, because the Telegram API is small and heavily documented. But you have to review the output before running it, and the review has three items, all three of which appear in this lesson. Put a strong model on the generation rather than the cheapest one; our current pick is in the AI section of this site.
- Write what the bot should do in plain language, as if explaining to an intern. Which commands, which answers, what it stores and where.
- Run the recipe below. Do not put the real token in the prompt; the recipe explicitly asks the model to read the token from an environment variable.
- Read the code before running it and take the same three items from the review sheet above through it: where the token is, how the 429 error is handled, and what gets read inside a group.
- Do the first run with a second bot rather than the real one. The documentation suggests exactly that: create a new bot, use its token in the test instance, and leave the real bot untouched.
Copy-ready recipe
Write a Telegram bot that does this:
{plain description of what the bot should do}
Strict rules:
1) Read the token from an environment variable and write no token in the code, not even as an example.
2) After every request, check the ok field of the response first and log the description value if it is false. Do not rely on the HTTP status code alone.
3) For sending to several people, put a delay between messages and handle the 429 error; do not send more than one message per second in a single chat.
4) Use getUpdates rather than a webhook, and recalculate the offset after each response.
5) Assume privacy mode is on in groups, so only process commands that are explicitly meant for this bot.
6) Wherever you are unsure whether the API has a method, leave a comment saying "must be checked in the documentation" instead of guessing, and carry on.
Output: the code only, plus a short list at the end of every Bot API method you used. Write no token, no real address and no version number.
Before you trust the output: Do not run the code that comes back until you have seen three things. One, that there is no token anywhere in the text. Two, that you have compared the method list at the end of the answer against the Bot API documentation; if a method is not in the docs, the model invented it and that piece of code will not work. Three, that if the bot is going into a group, it reads only what the privacy section above described. And do the first run with a test bot, not with one that has real users.
AI in this kind of work
A Telegram bot is one of the few places where generating code with a model genuinely beats learning first, because the API is small and its official documentation is full of examples. But that same smallness carries its own risk: a model easily invents a method that does not exist, and the code looks healthy at a glance. So put the model on the writing and the verification of methods on the documentation.
Tools that actually help
- Claude Good at writing the first version of a bot and at rereading the code it wrote. Iran is on neither of Anthropic two supported-countries lists; we read that on Anthropic own page.
- Claude Code Once the bot grows past one file, a command line tool works on the project itself and reads the logs too. Claude Code runs on the same Anthropic account, and Iran is not on the supported-countries list.
- Gemini Cost effective for summarising a documentation page and for simpler passes over code. Google own page says the Gemini web app runs in over 230 countries and territories, and Iran is not on that list.
Where it backfires
The first risk here is more concrete than in any other lesson of this track and its name is the token. Paste the bot token into a prompt and you have sent it to an external service, and because the token is the identity of the bot rather than a key beside a password, exposing it means somebody can message all of your users as you. Whether a service keeps your data for training depends on the plan and the settings of that service and is written on its own data usage page; but whatever the answer, sending the token is unnecessary. The recipe above deliberately asks the model to read the token from an environment variable.
The second risk is invented methods. The Telegram API has well formed names and a model easily produces one that looks like them and does not exist. The symptom shows up late, because the code compiles and you only get an unknown method error at runtime. That is why the recipe asks for the list of methods used at the end: compare that list against the documentation rather than the whole file.
And a point that is not code but belongs to this lesson: if your bot stores user messages anywhere, say so in the start message. Cybersecurity starts with sentences that simple. For how each tool can be paid for from Iran, see the buying guide.
Sources: Telegram Bot API: authorizing your bot and making requests Telegram: bot features, privacy mode and testing your bot Telegram bots FAQ: broadcasting limits and file sizes Anthropic: supported countries Google: where Gemini Apps are available
Where this advice stops
This lesson takes a simple bot to its first run and no further. Three things deliberately left out that a serious bot needs: storing conversation state when it has several steps, payment inside the bot, and scaling when a few thousand users message at once. All three are backend matters rather than Telegram API matters. Second, the numbers quoted here were read from the official FAQ today and Telegram changes them; look at that page again before leaning on any figure. Third, we said nothing about reaching Telegram from inside Iran because we have no citable claim about it; all we measured is that our own server reaches api.telegram.org.
From our own work
The answer shown in the second section was taken from our own server today rather than quoted from somewhere. We sent one request to https://api.telegram.org/bot123456:FAKE/getMe and what came back was this: {"ok":false,"error_code":401,"description":"Unauthorized"}. Three things follow from that one line and you can reproduce all three. First, the API returns a JSON envelope rather than an error page even for a wrong token, so your code has to read ok. Second, seeing that answer needs no bot at all, which means you can test connectivity before creating one. Third, and less comfortable: if a random string gets that answer, the correct string gets a different one, and that is exactly why this lesson insisted on where the token lives.
A small point from our own side: on this site the Telegram contact button in inc/helpers.php is a t.me link, which is the same deep linking mechanism the bot documentation describes. Every bot also has a link of the form https://t.me/<bot_username> and parameters can be added to it. That is the simplest way to take a user straight from a web page into a bot conversation, and most new projects leave it out.
Real follow-up questions
Does building a Telegram bot cost anything?
Creating the bot and getting a token is free, and the official FAQ says bots message their users at no cost by default. What costs money is elsewhere: the server your program stays up on. For a bot with a few hundred users, a small server is enough.
Do I have to know programming to build a bot?
The official FAQ says creating Telegram bots is super easy but that you will need at least some skill at computer programming. With AI help you can write a first version without mastery, but reading the code and understanding an error is still your job, and without it the bot stops the first time something breaks.
Can a bot read the messages in a group?
Not with the default setting; it only sees commands meant for it, replies to its messages, and inline messages sent via it. The mode can be turned off but Telegram itself says only where necessary, and group members can see its state in the member list. Bots that are group admins are the exception and receive all messages.