GLOSSARY

What is the Telegram Bot API?

The Telegram Bot API is Telegram's official HTTPS and JSON interface for bot accounts, reached at api.telegram.org/bot<token>/METHOD. Telegram runs the MTProto client for you on its own servers, which makes bots trivial to build but permanently unable to do the things only a logged-in user account can do.

Free forever plan · No credit card required · Cancel anytime

Quick definition

The Telegram Bot API is Telegram's official HTTPS and JSON interface for bot accounts, reached at api.telegram.org/bot<token>/METHOD. Telegram runs the MTProto client for you on its own servers, which makes bots trivial to build but permanently unable to do the things only a logged-in user account can do.

In a single sentence: Telegram runs the hard part, and charges you for it in capability rather than money.

What it means

The Telegram Bot API is a plain HTTPS interface. Every method is a URL of the form https://api.telegram.org/bot<token>/METHOD, every request is form-encoded or JSON, and every response is a JSON object with an ok boolean and either a result or an error_code and description.

Behind that URL, Telegram is running a real MTProto client on your behalf. It holds the connection, handles the encryption, resolves peers, manages access hashes, and translates the result into JSON. That is the whole value proposition: you get to write a Telegram integration with curl instead of implementing a bespoke binary protocol.

You get a bot by talking to @BotFather, which issues a token shaped like 123456789:AA.... The number before the colon is the bot's own user ID, which is why you can always tell a bot's ID by looking at its token, and why a leaked token is a leaked account. Tokens are revocable, which is the single biggest security advantage the Bot API has over a session string.

Two ways to receive updates

Bots do not maintain a persistent connection to your server. Telegram delivers events one of two ways, and enabling one disables the other.

Long polling with getUpdates: you ask for updates with an offset, the request hangs until something arrives or the timeout expires, and you acknowledge by passing the next offset on the following call. Updates are retained for 24 hours, so a bot that is offline overnight comes back to a backlog rather than to silence. It works from a laptop behind NAT, which is why it is the correct choice while developing.

Webhooks with setWebhook: Telegram POSTs each update to a URL you own. The endpoint has to be HTTPS on port 443, 80, 88 or 8443, with a certificate Telegram accepts (or a self-signed one you upload with the call). Webhooks push instead of pull, so they scale better and cut latency, and getWebhookInfo is the first place to look when a bot has gone quiet: it reports the pending update count and the last error message Telegram saw from your server.

One practical note that costs people hours: if your webhook endpoint returns a non-2xx status, Telegram retries, and the pending queue grows. A bot that "stopped working after a deploy" is very often a webhook pointed at a URL that now 502s, with a queue of thousands waiting behind it. See webhook for the general pattern.

The limits that actually bind

Telegram publishes some Bot API limits and enforces others by observation. The numbers in the table below are the ones that shape real architecture decisions. Two of them deserve emphasis.

The 20 MB download cap on getFile is asymmetric with what users can send. A customer can send your support bot a 200 MB screen recording, and your bot will receive the update, see the file metadata, and be unable to fetch the bytes. If your product handles user-supplied media, this alone can force you onto the local Bot API server or onto MTProto.

The 48-hour edit and delete window is the other one. A bot cannot edit or delete a message older than 48 hours, full stop. Any feature built on "we will clean that up later" needs to run inside the window or not exist.

What a bot fundamentally cannot do

These are not limits you can raise. They are consequences of what a bot account is.

  • Start a conversation. The user must message the bot, add it to a group, or open it through a deep link first.
  • Read history from before it joined. A bot added to a group today sees nothing that happened yesterday.
  • Enumerate group members. There is no method for it. Admins yes, member count yes, member list no.
  • Join a group by invite link. A human has to add it.
  • See non-command group messages by default. Privacy mode is on until you turn it off in BotFather.

Everything on that list is available to a userbot, which is a real user account driven over MTProto. That is the actual trade: the Bot API gives you a supported, revocable, unbannable-for-volume identity that cannot do outbound, and a user account gives you full capability with real account risk. Most serious Telegram products end up running both.

Why it matters

Choosing between the Bot API and MTProto is the first architectural decision in any Telegram integration, and it is expensive to reverse, because the two speak different peer identifiers, deliver updates differently, and have entirely different failure modes.

The decision usually comes down to direction of contact. If people come to you, a bot is the right tool: support inboxes, order notifications, internal alerts, appointment reminders, payment flows, and anything with buttons, because inline keyboards and callback queries are bot-only features. If you need to go to people, or to read a group you do not own, no amount of Bot API engineering will get you there.

The second consideration is risk. A bot token is revocable and a bot is not going to get a phone number banned. A user account is a real person's identity, subject to flood waits, PEER_FLOOD, and permanent restriction. Teams that treat those as interchangeable tend to discover the difference at the worst possible moment.

Common mistakes

  • Putting the token in a client-side bundle. The token is the account. It belongs on your server, and only there.
  • Ignoring retry_after. A 429 tells you exactly how long to wait. Retrying immediately extends the penalty.
  • Returning 500 from the webhook handler on business errors. Telegram will retry the same update forever. Acknowledge with a 200 and handle the failure in your own queue.
  • Forgetting privacy mode. The bot works perfectly in a private chat and appears broken in groups, and nothing in the API tells you why.
  • Assuming chat_id is the MTProto ID. It is not. See peer ID for the conversion.
  • Building an outbound campaign on a bot. It cannot message strangers. This is discovered surprisingly late.

Related concepts

  • MTProto: the protocol the Bot API is a managed wrapper around.
  • Userbot: the other side of the trade, with full capability and full risk.
  • Business connection: Telegram's sanctioned way to let a bot answer a real person's private chats.
  • Peer ID: why a Bot API chat_id looks nothing like the MTProto ID for the same chat.
  • Forum topic: the message_thread_id a bot must echo back to reply in the right thread.
  • Webhook: the delivery pattern, and how to make it reliable.

How Pinlyx handles it

Pinlyx runs both paths and routes each job to whichever one can actually perform it. Bot traffic arrives over a webhook, is acknowledged immediately, and is processed from an internal queue, so a slow downstream never turns into a growing pending-update backlog. Rate limits are respected on both sides: the Bot API client honours retry_after, and the MTProto sender handles FLOOD_WAIT with exponential back-off. Anything a bot can do, a bot does, because it carries no account risk. Anything that requires reaching a person who has not written first runs through a connected user account inside the Telegram CRM, under a rate limiter with per-account hourly and daily caps.

Reference · the numbers that bind

Bot API limits worth designing around.

Some of these are documented, some are enforced by observation. All of them will shape your architecture eventually.

Messages to different users

about 30 per second

The global ceiling for a single bot. Sustained bursts above it return 429 rather than queueing.

Messages to one chat

about 1 per second

Short bursts are tolerated, but a loop that sends five messages to one chat back to back will hit this.

Messages to one group

about 20 per minute

Notably stricter than private chats. Group notification bots need their own pacing.

File download via getFile

20 MB

Hard limit on the hosted API. A user can send your bot a 2 GB video that the bot then cannot fetch.

File upload

10 MB photos, 50 MB other files

Also a hosted-API limit. Both ceilings lift dramatically if you run the open-source local Bot API server.

Editing and deleting

48 hours

A message can only be edited or deleted by a bot within 48 hours of being sent. After that the API refuses.

Cheat sheet · request and error shapes

What success and failure look like.

Every Bot API response uses the same envelope, which makes error handling mechanical once you know the three you will actually see.

POST https://api.telegram.org/bot<token>/sendMessage
{ "chat_id": -1001234567890, "text": "Order #4471 shipped" }

// Success
{ "ok": true, "result": { "message_id": 8123, "date": 1757251200, ... } }

// Rate limited: the Bot API's version of a flood wait
{
  "ok": false,
  "error_code": 429,
  "description": "Too Many Requests: retry after 32",
  "parameters": { "retry_after": 32 }
}

// The user blocked the bot. Not retryable, ever.
{
  "ok": false,
  "error_code": 403,
  "description": "Forbidden: bot was blocked by the user"
}

// Group was upgraded to a supergroup: the chat_id you stored is dead
{
  "ok": false,
  "error_code": 400,
  "description": "Bad Request: group chat was upgraded to a supergroup chat",
  "parameters": { "migrate_to_chat_id": -1001234567890 }
}
// Telegram hands you the new id in parameters. Store it and retry once.

403 is permanent

Blocked by the user. Mark the contact unreachable rather than queueing a retry.

429 is arithmetic

Sleep retry_after plus a margin. The number is not a suggestion.

400 can be recoverable

A migration error carries the replacement chat ID in parameters.

Choose in one question

Who initiates the conversation?

If the answer is "the customer", build a bot. Support inboxes, order updates, booking flows, internal alerts, anything with buttons: all of it is easier, safer and more reliable on the Bot API, and inline keyboards are a bot-only feature that a user account cannot replicate.

If the answer is "we do", the Bot API is not an option at any level of effort. Cold outreach, group member research, and reading conversations that predate your integration all require a user account over MTProto, and that decision brings account warm-up, pacing, rotation and flood-wait handling along with it.

Watch out for

Privacy mode makes a working bot look broken.

A brand new bot works perfectly in a one-to-one chat, gets added to a group, and receives almost nothing. No error, no warning, no log entry. Privacy mode is enabled by default and filters everything except commands, mentions, replies to the bot, and service messages.

Fix it with /setprivacy in BotFather. The part people miss: the change does not apply retroactively to groups the bot is already in. Remove the bot and add it back.

Telegram Bot API: FAQ

The questions that decide whether a bot can do the job at all.

No. A user has to start the bot, add it to a group, or send it a message before the bot can write to them. This is not a rate limit or a setting, it is the design: the Bot API never gives your bot a way to reference a user it has not met. If your use case is cold outbound, the Bot API cannot do it at any price, and the only alternative is a user account over MTProto, with all the risk that carries.
Privacy mode is on by default for every new bot. In a group, a bot with privacy mode enabled only receives messages that start with a slash command, mention the bot by username, are replies to one of its own messages, or are service messages. Everything else is invisible to it. You turn it off with /setprivacy in BotFather, and you have to remove and re-add the bot to existing groups for the change to take effect there.
They are mutually exclusive, so you have to pick. getUpdates long polling is easier to develop against, works behind NAT, and needs no certificate, which makes it the right choice locally and for low-traffic bots. A webhook is push instead of pull, so it scales better and has lower latency, but it requires a public HTTPS endpoint on port 443, 80, 88 or 8443 with a valid certificate. In production the usual answer is a webhook, with getUpdates kept for local development.
As HTTP 429 with a JSON body whose description reads "Too Many Requests: retry after N" and a parameters object containing retry_after in seconds. It is the Bot API equivalent of the FLOOD_WAIT error you get over MTProto, and the correct handling is identical: sleep for at least the stated interval, add a small margin, and back off further if the retry also fails.
No to both. getChatAdministrators returns the admins and getChatMemberCount returns a number, but there is no method that enumerates ordinary members, and getChatMember requires a user ID you already have. Nor can a bot read messages sent before it joined. Both restrictions are deliberate anti-scraping measures, and they are the main reason CRM products that need group data run MTProto user accounts alongside their bots.
Telegram open-sourced the Bot API server itself, so you can run the same binary on your own infrastructure and point your bot at it instead of api.telegram.org. The main reasons to do it are the file limits, which rise into the gigabytes, the ability to work with local file paths rather than uploads, and the higher webhook connection limits. It does not lift the messaging rate limits, because those are enforced by Telegram, not by the API layer.
Ready to ship

Bots for inbound. Real accounts for outbound.

Pinlyx runs both, routes every message to the path that can actually deliver it, and respects the limits on each side automatically.

Free forever plan · GDPR-ready · No credit card required

We value your privacy

We use cookies to improve our site, analyze traffic, and personalize ads. You can accept all, reject non-essential, or customize your choices. Read our Cookie Policy.