Handling Callbacks (Inline Buttons)¶
Reply keyboards sit below the text entry field. Inline buttons, on the other hand, sit directly inside the message bubble. Tapping an inline button doesn't send a normal chat message; instead, it triggers a callback query that runs code silently in the background.
This is perfect for "Yes / No" confirmations, pagination ("Next Page"), or toggle settings without cluttering the chat.
Step 1: Send Inline Buttons in Logic¶
Unlike reply keyboards, inline keyboards must be generated programmatically inside the Logic field using Api.sendMessage.
Create a command named /buttons and paste this into its Logic field:
await Api.sendMessage({
chat_id: chat.id,
text: "Choose your favorite fruit:",
reply_markup: {
inline_keyboard: [
[
{ text: "🍎 Apple", callback_data: "pick_apple" },
{ text: "🍌 Banana", callback_data: "pick_banana" }
]
]
}
});
textis what the user sees on the button.callback_datais the hidden payload sent to your bot when clicked (maximum 64 bytes).
Step 2: Create matching handler commands¶
When a user taps the "Apple" button, Telegram fires pick_apple. TBL treats this payload exactly like a command name!
Let's create two new commands to handle these button taps:
Create the pick_apple command:¶
- Click Add Command.
- Command: Type
pick_apple(matchescallback_data). - Logic: Paste this code:
// 1. Tell Telegram to stop showing the button's loading spinner await Api.answerCallbackQuery({ callback_query_id: update.callback_query.id, text: "You picked Apple!" }); // 2. Edit the message to clean up the screen await Api.editMessageText({ chat_id: chat.id, message_id: update.callback_query.message.message_id, text: "🍎 You selected Apple. Delicious!" }); - Save the command.
Create the pick_banana command:¶
- Click Add Command.
- Command: Type
pick_banana. - Logic: Paste this code:
- Save the command.
Two Golden Rules of Inline Buttons¶
Rule 1: Always answer the callback!¶
When a user clicks an inline button, Telegram shows a loading spinner on that button. If you don't call Api.answerCallbackQuery(), the spinner will spin for up to 10 seconds. Always call it!
Rule 2: Message variables change in callbacks¶
Because callbacks aren't standard text messages, the global variable message is null. Instead, use update.callback_query to fetch context:
update.callback_query.id➔ Required to answer the callback query.update.callback_query.data➔ The button'scallback_datapayload.update.callback_query.message.message_id➔ The ID of the message bubble the buttons are attached to (required to edit the message).
Test It!¶
- Open Telegram and send
/buttonsto your bot. - Tap the 🍎 Apple button.
- The loading spinner will disappear, a quick popup (toast notification) saying "You picked Apple!" will show up, and the message text will edit itself to: "🍎 You selected Apple. Delicious!".
What's Next?¶
We've covered structured commands and menus. But what happens if a user types something completely random like "skdfjldsf"? In the final step, we'll build a catch-all command!