In short
After a callback_data tap you must call answerCallbackQuery within 300 seconds or the button keeps spinning. Supported fields: callback_query_id, text (≤200), show_alert. Not supported: url, cache_time. Then optionally editMessageReplyMarkup / editMessageText.
Overview
Message callbacks are open. MiniApp client return flows (web_app_data / sendData / answerWebAppQuery) stay closed — do not confuse the two. Details: core.mp.net/bots.
Why you must answer
The client shows a loading state on the button until answerCallbackQuery succeeds (or the 300s window expires). Omitting or emptying text only clears loading. Repeated answers are idempotent.
Event flow
User taps an inline button with
callback_data.Your webhook /
getUpdatesreceivescallback_query(include it inallowed_updates).Handle business logic, then
answerCallbackQuery.Optionally
editMessageReplyMarkupand/oreditMessageTexton the same bubble.
answerCallbackQuery parameters
Field | Required | Notes |
| yes |
|
| no | Toast/Alert body; max 200. Empty/omit = stop spinner only. |
| no | If true, prefer an alert dialog over a toast. |
Official limits
url and cache_time from Telegram are not supported and must not be sent.
POST https://call.mp.net/bot/bot<token>/answerCallbackQuery
{
"callback_query_id": "callback-message-uid",
"text": "Done",
"show_alert": false
}
editMessageReplyMarkup vs editMessageText
editMessageReplyMarkup: replace or clear buttons only (chat_id+message_id); omit / null / emptyinline_keyboardremoves buttons.inline_message_idis not supported; non-text / non-Inline media messages cannot use this path.editMessageText: change the text body (and optionally keyboard) of a bot-authored editable message.Neither path invents a new message id for the same bubble.
copy_text does not use this path
copy_text is handled on-device. You will not receive callback_query and must not call answerCallbackQuery.
allowed_updates
For webhooks, set allowed_updates to include callback_query (e.g. ["message", "callback_query"]) or omit the field to receive all supported types. Polling follows the same Update shape.
Failure modes
No answer within 300s → client spinner / expired query.
Double-taps: answer once; further answers are idempotent.
Stale
callback_query_id→ API error; refresh the keyboard witheditMessageReplyMarkupif needed.
Related
Inline keyboard buttons: url, web_app, callback_data, copy_text
Polling vs webhook (allowed_updates)
API method matrix / core message methods
