The easiest way to set up a chat with your Telegram bot

A simple CLI script to start a chat with a bot and output the chat ID

Author's image
Tamás Sallai
3 mins

Telegram chatbots

I started experimenting with Telegram chatbots only recently, and I'm amazed by how versatile they can be. With commands, a webhook, and a realtime communication channel between a server I own and my phone, they can be used to monitor and manage quite everything. Since it's mostly about how I implement the different commands, I can have a chatbot that starts/stops EC2 instances, query the status of services, or even open a door.

It's all great, but what about just able to send a message to myself? After all, it's easier than email, as I only need 2 things: a bot token and the chat ID. Then a single line sends a message to the chat:

curl -X POST -d 'chat_id=${chatId}' -d 'text=abc' https://api.telegram.org/bot${token}/sendMessage

The bot token is what BotFather gives you when you create the bot:

But how to get the chat ID?

Chat ID

The chat ID is an internal identifier that the bot gets and it identifies the chat session users started with the bot. It is sent with every update:

{
	"update_id": 794048666,
	"message": {
		"message_id": 53,
		"from": {
			...
		},
		"chat": {
			"id": "...",
			"..."
		},
		"date": 1642935026,
		"text": "test"
	}
}

So, all the bot needs to do is to wait for a message, get the update, then extract this ID. This then provides a direct channel back.

I needed to do this repeatedly, so I made a package that makes this process simple.

Using the telegram-bot-setup package

To get a chat ID, run the command:

npx telegram-bot-setup

This asks for the bot token and outputs a QR code:

Scan the QR, then start a chat with the bot:

When you press "Start", the script exits with the entered data and the chat ID:

TOKEN: 5242405565:AAE3iUNVjO3dKYBthFjFW0w4tknwNq8iW2c
CHAT_ID: 1588718028
curl -X POST -d 'chat_id=1588718028' -d 'text=abc' -d 'disable_notification=true' https://api.telegram.org/bot5242405565:AAE3iUNVjO3dKYBthFjFW0w4tknwNq8iW2c/sendMessage

How does it work

First, it sends the getMe request to find out the username of the bot. This is needed to construct the URL that starts the chat with the bot.

const username = (await sendTelegramCommand("getMe", {})).username;

Then it generates a random string that is the start token. This will be part of the deep link and the script will check for this token in the start message. This is needed to prevent another user starting a chat instead of you.

const startToken = crypto.randomBytes(16).toString("hex");

The start link:

const url = `https://t.me/${username}?start=${startToken}`;

Then it starts polling for updates and stops when a /start ${startToken} is found:

const checkMessages = async (offset) => {
	const messages = await sendTelegramCommand("getUpdates", {timeout: 10, offset});
	const startMessage = messages.find((message) => {
		return message.message?.text === `/start ${startToken}`;
	});
	if (startMessage) {
		return startMessage.message.chat.id;
	}else {
		const maxUpdateId = Math.max(offset, ...messages.map(({update_id}) => update_id));
		return checkMessages(maxUpdateId + 1);
	}
};

The offset is needed to "acknowledge" messages when using the getUpdates command.

Finally, when there is a matching start message, it prints the chat ID:

const chatId = await checkMessages(0);
console.log(`TOKEN: ${token}\nCHAT_ID: ${chatId}`);
April 19, 2022
In this article