In short
Reply Keyboard is the right-side custom keyboard under the input. Send it with sendMessage reply_markup = ReplyKeyboardMarkup. A normal button sends a user message whose text is the button label — not a callback_query. It is independent from the left Menu Button.
Overview
Use Reply Keyboard for persistent or one-shot shortcuts. For buttons that stay on a message bubble and call your backend with callback_data, use Inline Keyboard instead. Official reference: core.mp.net/bots.
Send via reply_markup
Pass a ReplyKeyboardMarkup object as reply_markup on sendMessage (also accepted on other message-sending methods that support the ReplyMarkup union). Discriminator fields must match exactly one markup type.
{
"chat_id": 12345,
"text": "Choose an action",
"reply_markup": {
"keyboard": [[{ "text": "Status" }, { "text": "Help" }]],
"resize_keyboard": true,
"is_persistent": true
}
}
Normal buttons → message.text (not callback_query)
When the user taps a plain text button, the client sends a normal message.
Your Update contains
message.textequal to the button label.Do not expect
callback_query— that path is for Inlinecallback_databuttons only.
is_persistent / one_time_keyboard / remove
Field / markup | Behavior |
| Requests the keyboard stay available (client keeps offering the toggle). |
| Collapses after one use, but the user can usually summon it again from the toggle. |
| Deletes the effective Reply Keyboard state for the chat (true remove). |
Do not confuse with Menu Button
setChatMenuButton never creates, removes, or expands a Reply Keyboard. To hide the custom keyboard, send ReplyKeyboardRemove, not a menu API call.
selective in groups
In groups, set selective: true so the keyboard is shown only to users mentioned in the message / the sender of the replied-to message (Telegram-compatible selective semantics). Without it, the keyboard may apply more broadly in that chat.
Privacy Mode caveat
Privacy Mode
If the bot runs with Privacy Mode enabled in a group, it may only see commands, mentions, and replies to the bot. A Reply Keyboard press that sends plain text without being a command or a reply to the bot may not reach your backend. Prefer slash-command labels, require reply context, or disable Privacy Mode when the product needs every button tap.
web_app button: private chat only
A Reply Keyboard button with web_app is intended for private chats. Do not rely on it in groups. Ownership / URL rules for keyboard web_app follow the message button path on core.mp.net/bots (stricter than Menu Button web_app, which allows any HTTPS ≤2048).
Independence from Menu Button
Left Menu Button ↔
setChatMenuButton.Right Reply Keyboard ↔ message
reply_markuponly.Both can be present at once; neither API drives the other.
Related
Chat menu button: setChatMenuButton (commands, web_app, default)
Inline keyboard / callback guides (when published in this collection)
