How to build a reliable, scalable, and cost-effective Telegram bot

Daniel Bojczuk
WAES
Published in
10 min readJul 1, 2022

You are probably asking yourself: why should I build a Telegram Bot? Well, you don’t need it. Still, I’ll show you that you can learn some good stuff using this Telegram bot, and if you have a good idea, you can make some money with it.

What is and why Telegram

Telegram is an instant messenger app, like WhatsApp or Facebook Messenger. Maybe Telegram is not the most known app, but it has a simple and lovely API. It allows us to use Telegram as a frontend layer, letting our bot be the backend. You can even use CSS + HTML5 in your bot responses.

If you go through their API Terms of Service, you can check they explicitly allow you to monetize your apps:

Developers are allowed to monetize their coding efforts through advertising or other legitimate means.

Adding to this the fact that they are growing in the number of users daily, and you can have your bot triggered by a WebHook (don’t worry, we will get back to this later), Telegram seems to be an excellent choice for creating a bot.

How does Telegram works?

There are two basic steps to creating a bot. The first one is creating your bot. To accomplish this step, you will need to use a telegram bot to make yours: the Bot Father (how convenient, uh?!).

It will provide you with a token that will allow you to manage your bot and receive/read messages. This brings us to my only security concern about Telegram bots: If you lose this token, you lose your bot. So keep it safe!

The second one is not mandatory, but you can configure how you want your backend to receive your messages:

  • Telegram API Calls: Your backend calls the telegram API asking for the messages. This is the default one.
  • WebHook: As soon as your bot receives a message, Telegram will call your API, passing the message.

For our scenario, I prefer the WebHook method so we can use the event-driven architecture pattern.

Planning our bot

Let’s start setting our goals for our bot:

  • The bot should be reliable. We must ensure that our bot will always be ready to process the messages. So we take advantage of the cloud provider reliability as much as possible.
  • The bot should be scalable. The bot should scale as much as necessary or, at least, as much as our budget can afford.
  • The bot should be cost-effective. It doesn’t matter if you create this bot to learn something new or create it to run in a production environment. We want to spend as less money as we can.

So, based on the Telegram specifications and our goals, I set these three characteristics:

  • Asynchronous communication. Most people don’t mind waiting a few seconds to receive an answer from an instant message. So we can take advantage of that! (But don’t worry, our bot will mostly take less than 1 second to answer)
  • Serverless architecture. When we talk about event-driven architecture, asynchronous communication, and cost-effectiveness, Serverless always comes to my mind. So let’s use its advantages in our project.
  • AWS Hosted Application. AWS provides excellent Serverless services and integrations. Let’s use them to our benefit.

Simple Architecture Diagram

With all the above information, this is the diagram we will implement:

Receiving the message from Telegram

Since we are using asynchronous communication, a queue seems to be a good choice, and we will use the AWS SQS. It would be perfect if Telegram could POST our message directly into the queue (Inbound Queue), but AWS requests authorization, authentication, and a specific payload that Telegram won’t provide. To solve that, we will use the beauty of AWS Serverless and configure our API Gateway to post directly to the SQS.

Processing the message

We’ll use a Lambda function (Inbound Lambda Function) to process the message. You can do whatever you want here, but in this article, we will generate an answer containing “You typed: ” plus the received message.

Sending the answer to Telegram

We could easily make the same Lambda function to send the answer. I didn’t do it and created another queue (Outbound Queue) and lambda function (Inbound Lambda Function) for two reasons:

  • Decoupling other behaviors can help you with your coding. So if you can split the behaviors of your application into different Lambda functions, do it!
  • Thinking about the further steps, if you would like to send another kind of message to your clients generated by another service, you won’t need to implement the response logic again. You’ll only need to post in the existing queue.

Do you remember that we need to keep our Telegram Bot token safe? I stored it in the Secret Manager and wrote a code in the Outbound Lambda Function to retrieve it before sending the response to Telegram.

Implementing the bot

This article would get too long and tedious if I went through all the implementation details. So I’ll show here the basic steps on how to:

  • Create an SQS queue.
  • Create an API Gateway and integrate it with the SQS
  • Create a Lambda Function and integrate it with SQS.
  • Create a Telegram Bot
  • Set the Telegram Bot to use the WebHook

With these items and the architecture diagram, you will be able to build your bot. If you want to get more details, you can:

  • Check the second presentation from this WAES TechTalk. I implemented and tested this bot live. And you will also understand why this was the batata presentation.
  • Check (and collaborate with) this GitHub repository containing the Terraform scripts and source codes for this project.

Creating an SQS queue

To create a queue in AWS, search for SQS in the services bar and open the Simple Queue Service.

Then you can click on the “Create queue” button:

Since I want the messages to be handled in the same order they were received, for this bot, I considered it essential to create a FIFO queue. So change the type to FIFO and provide a name.

Go down and click the “Create Queue button,” and we are done.

Repeat the same steps to the outbound queue.

Creating an API Gateway

To create an API Gateway in AWS, search for “API Gateway” in the services bar and open it.

Then choose the REST API type and click on “Build”.

Chose the “New API” option, provide a name and click on “Create API”.

Let’s create a resource in our API gateway. Click on “Actions”, then on “Create Resource”.

Provide a resource name and path, and click “Create Resource”.

Since Telegram needs us to provide an endpoint with a POST method, let’s do that. Select your resource, click “Actions”, then “Create Method”, select “POST”, and confirm.

Next, we must set the API Gateway to integrate directly into the SQS queue. For the integration type, select “AWS Service”. In “AWS Region”, choose the region you are currently using. The “AWS Service” must be SQS. The “HTTP method” should be POST, and we will select “Use path override,” defining the path override as our account id slash inbound queue name. For the “Execution role”, you must choose/create one that allows the SQS Server to post into the inbound queue. You can keep the other options with the default value and click “Save”.

These steps have already created an integration with the correct authorization and authentication. Now, we need to configure the API gateway to transform the request sent by Telegram to the SQS necessary headers and payload. So we need to add some additional configuration to the Integration request.

Click “Integration Request”, expand the “HTTP Headers” section, and add the following header:

We need to add a mapping template to send the expected body to SQS. Expand the “Mapping Templates” section. In the “Request Body Passthrough”, select “Never”, click “Add mapping template”, fill the content-type with application/JSON, and confirm.

In the template, fill with the expected body and click “Save”. If you pay attention, in the “MessageBody” field, I’m sending the received body encoded in base64. That is necessary because the telegram can send us some special characters that will break the template.

Now, our API Gateway sends the messages directly to the SQS queue.

Creating a Lambda function

AWS Lambda is a serverless computing service that runs when it is triggered. In our case, we will create a Lambda function triggered by an SQS message.

The creation of a Lambda function is pretty straightforward. Search for the Lambda function in the service bar.

Click “Create function”, provide a name, and choose the runtime that, in our case, will be NodeJS 16. For the architecture, I decided on arm64 for the price and performance, but you can also select x86_64 if you want.

Expand the “Change default execution role” section, and in the “Execution role”, you need to provide one that allows the Lambda function POST messages into the outbound queue. Then you can click “Create function”.

To add an SQS message as a trigger, click on ‘Add trigger’, choose SQS, and provide the queue name. The code from my GitHub repository doesn’t support more than one message per execution since it is an example. If you are using it, you must set the Batch size to 1 and the Batch window to 0.

After uploading the source code, your Lambda function will be ready.

Create a Telegram Bot

In the telegram, start talking to the Bot Father and send on the chat the following command: /newbot. The Bot Father will ask you to provide a name, then a username. After that, it will give you the token you need to interact with your bot.

Set the Telegram Bot to use the WebHook

To Telegram be able to call our API gateway as soon as there is a new message, we need to set the WebHook. To accomplish this, we will need to call the telegram API being {TOKEN} the token provided by Bot Father and {APIGatewayURL} the URL from our API.

curl --location --request POST 'https://api.telegram.org/bot{TOKEN}/setWebhook?url={APIGatewayURL}'

Costs

One of this project’s goals is to be cost-effective, right? So if you look at the pricing calculator, you will pay $13,73 per month to receive and answer 1.000.000 messages. For this calculation, I’m not using the AWS free tier. If you consider it, you will pay even less.

If you don’t handle any messages, you will pay $0,40 per month for the Secrets Manager. I really think it is worth it.

Next Steps

We already can think about some improvements:

  • Make the source code handle more than one message per execution.
  • Remove the necessity to go to Secrets Manager in every response to Telegram.
  • Implement some metrics and alarms.
  • Implement dead letter queues to handle possible errors.
  • Define some limits to concurrent execution.

Would you like to implement them, or do you have any other ideas? Comment on this article and submit Issues and Pull Request to the GitHub repository.

Do you think you have what it takes to be one of us?

At WAES, we are always looking for the best developers and data engineers to help Dutch companies succeed. If you are interested in becoming a part of our team and moving to The Netherlands, look at our open positions here.

WAES publication

Our content creators constantly create new articles about software development, lifestyle, and WAES. So make sure to follow us on Medium to learn more.

Also, make sure to follow us on our social media:
LinkedInInstagramTwitterYouTube

--

--

Daniel Bojczuk
WAES
Writer for

Dad, husband and Software Engineer in The Netherlands