Question: i'd like to send a message through telegram bot with buttons. Once button is pressed i need to know which button was that and then change the text that came with the button. I've almost found out how to do things separately but i can't unite them. To send a message with buttons i need either to write /start or have to press a menu button. I need those buttons to appear after the message without user having to press anything. This is a script that i've found in the official description with added functions to send a message #!/usr/bin/env python # pylint: disable=unused-argument, wrong-import-position # This program is dedicated to the public domain under the CC0 license. """ Basic example for a bot that uses inline keyboards. For an in-depth explanation, check out https://github.com/python-telegram-bot/python-telegram-bot/wiki/InlineKeyboard-Example. """ import logging import asyncio from telegram import __version__ as TG_VER try: from telegram import __version_info__ except ImportError: __version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment] if __version_info__ < (20, 0, 0, "alpha", 1): raise RuntimeError( f"This example is not compatible with your current PTB version {TG_VER}. To view the " f"{TG_VER} version of this example, " f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html" ) from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram.ext import ApplicationBuilder, Application, CallbackQueryHandler, CommandHandler, ContextTypes # Enable logging logging.basicConfig( format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO ) # set higher logging level for httpx to avoid all GET and POST requests being logged logging.getLogger("httpx").setLevel(logging.WARNING) logger = logging.getLogger(__name__) async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Sends a message with three inline buttons attached.""" keyboard = [ [ InlineKeyboardButton("Option 1", callback_data="1"), InlineKeyboardButton("Option 2", callback_data="2"), ], [InlineKeyboardButton("Option 3", callback_data="3")], ] reply_markup = InlineKeyboardMarkup(keyboard) await update.message.reply_text("Please choose:", reply_markup=reply_markup) async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Parses the CallbackQuery and updates the message text.""" query = update.callback_query # CallbackQueries need to be answered, even if no notification to the user is needed # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery await query.answer() await query.edit_message_text(text=f"Selected option: {query.data}") async def help_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Displays info on how to use the bot.""" await update.message.reply_text("Use /start to test this bot.") # using telegram.Bot async def send(chat, msg): await Bot('<TOKEN>').sendMessage(chat_id=chat, text=msg) # using ApplicationBuilder async def send_more(chat, msg): application = ApplicationBuilder().token('<TOKEN>').build() await application.bot.sendMessage(chat_id=chat, text=msg) def main() -> None: """Run the bot.""" # Create the Application and pass it your bot's token. application = Application.builder().token("<TOKEN>").build() # asyncio.run(send_more('<CHAT_ID>', 'Hello there!')) application.add_handler(CommandHandler("start", start)) application.add_handler(CallbackQueryHandler(button)) application.add_handler(CommandHandler("help", help_command)) asyncio.run(send('<CHAT_ID>', 'Hello there!')) # Run the bot until the user presses Ctrl-C application.run_polling(allowed_updates=Update.ALL_TYPES) if __name__ == "__main__": main()  <<< EDIT >>> The new code: #!/usr/bin/env python # pylint: disable=unused-argument, wrong-import-position # This program is dedicated to the public domain under the CC0 license. """ Basic example for a bot that uses inline keyboards. For an in-depth explanation, check out https://github.com/python-telegram-bot/python-telegram-bot/wiki/InlineKeyboard-Example. """ import logging from telegram import __version__ as TG_VER try: from telegram import __version_info__ except ImportError: __version_info__ = (0, 0, 0, 0, 0) # type: ignore[assignment] if __version_info__ < (20, 0, 0, "alpha", 1): raise RuntimeError( f"This example is not compatible with your current PTB version {TG_VER}. To view the " f"{TG_VER} version of this example, " f"visit https://docs.python-telegram-bot.org/en/v{TG_VER}/examples.html" ) from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup, Update from telegram.ext import ApplicationBuilder, Application, CallbackQueryHandler, CommandHandler, ContextTypes # Enable logging logging.basicConfig( format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", level=logging.INFO ) # set higher logging level for httpx to avoid all GET and POST requests being logged logging.getLogger("httpx").setLevel(logging.WARNING) logger = logging.getLogger(__name__) prolong_1y = 0 prolong_2y = 0 noprolong = 0 async def button(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: """Parses the CallbackQuery and updates the message text.""" query = update.callback_query # CallbackQueries need to be answered, even if no notification to the user is needed # Some clients may have trouble otherwise. See https://core.telegram.org/bots/api#callbackquery await query.answer() global prolong_1y, prolong_2y, noprolong if "prolong_1y" in query: prolong_1y = 1 prolong_2y = 0 noprolong = 0 elif "prolong_2y" in query: prolong_1y = 0 prolong_2y = 1 noprolong = 0 elif "noprolong" in query: prolong_1y = 0 prolong_2y = 0 noprolong = 1 await query.edit_message_text(text=f"Selected option: {query.data}") print(f"prolong_1y => {prolong_1y}, prolong_2y => {prolong_2y} and noprolong => {noprolong}") # using telegram.Bot async def send(chat, msg, reply_markup): await Bot('<TOKEN>').sendMessage(chat_id=chat, text=msg, reply_markup=reply_markup) async def post_init(application: Application) -> None: """Sends a message with three inline buttons attached.""" keyboard = [ [ InlineKeyboardButton("Option 1", callback_data="prolong_1y"), InlineKeyboardButton("Option 2", callback_data="prolong_2y"), ], [InlineKeyboardButton("Option 3", callback_data="noprolong")], ] reply_markup = InlineKeyboardMarkup(keyboard) await send('<CHAT_ID>', 'Hello there!', reply_markup) def main() -> None: """Run the bot.""" # Create the Application and pass it your bot's token. application = Application.builder().token("<TOKEN>").post_init(post_init).build() application.add_handler(CallbackQueryHandler(button)) # Run the bot until the user presses Ctrl-C application.run_polling(allowed_updates=Update.ALL_TYPES) if __name__ == "__main__": main()  The error that i receive after pressing on either Choice button: 2023-07-19 13:50:13,278 - apscheduler.scheduler - INFO - Scheduler started 2023-07-19 13:50:13,278 - telegram.ext.Application - INFO - Application started 2023-07-19 13:50:16,557 - telegram.ext.Application - ERROR - No error handlers are registered, logging exception. Traceback (most recent call last): File "/home/admin2/.local/lib/python3.11/site-packages/telegram/ext/_application.py", line 1173, in process_update await coroutine File "/home/admin2/.local/lib/python3.11/site-packages/telegram/ext/_basehandler.py", line 141, in handle_update return await self.callback(update, context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/media/smb_general/Адміністрування/Source/ElReports/elreports/inlinekeyboard.py", line 50, in button if "prolong_1y" in query: ^^^^^^^^^^^^^^^^^^^^^ File "/home/admin2/.local/lib/python3.11/site-packages/telegram/_telegramobject.py", line 247, in __getitem__ return getattr(self, item) ^^^^^^^^^^^^^^^^^^^ TypeError: attribute name must be string, not 'int'  <<< EDIT 2 >>> Silly me, changed query to query.data now everything works!

Answer: If you want to attach buttons to the message sent in send, you can just use the corresponding parameter of send_message for that. Not that message.reply_text as used in start is just a shortcut for that method. Moreover, you don't need to manually initialize a bot in send and to manually run that method via asyncio.run. I recommend to instead make use of post_init which allows to run a custom logic as part of the startup logic of application.run_polling.  Disclaimer: I'm currently the maintainer of python-telegram-bot.