editMessageReplyMarkup
Use this method to edit only the reply markup of messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent.
Parameters
business_connection_idStringOptionalUnique identifier of the business connection on behalf of which the message to be edited was sent
chat_idIntegerStringOptionalRequired if inline\message\id is not specified. Unique identifier for the target chat or username of the target channel (in the format
@channelusername)message_idIntegerOptionalRequired if inline\message\id is not specified. Identifier of the message to edit
inline_message_idStringOptionalRequired if chat\id and message\id are not specified. Identifier of the inline message
A JSON-serialized object for an inline keyboard.
Returns
On success, Message | True is returned.
GramIO Usage
ts
// Replace the keyboard on a message after a button press
bot.on("callback_query", async (ctx) => {
const updatedKeyboard = new InlineKeyboard()
.text("Option A ✓", "opt_a_done")
.row()
.text("Back", "go_back");
await ctx.editReplyMarkup(updatedKeyboard);
await ctx.answer();
});ts
// Build a multi-step wizard — swap keyboards between steps
bot.on("callback_query", async (ctx) => {
if (ctx.queryPayload === "step_1") {
const step2Keyboard = new InlineKeyboard()
.text("Continue →", "step_2")
.text("Cancel", "cancel");
await ctx.editReplyMarkup(step2Keyboard);
}
await ctx.answer();
});ts
// Direct API call — remove the inline keyboard from a message
await bot.api.editMessageReplyMarkup({
chat_id: 123456789,
message_id: 42,
// omit reply_markup to remove the existing keyboard
});Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: message is not modified | New keyboard is identical to the current one — check before calling |
| 400 | Bad Request: message can't be edited | Message too old, sent by another bot, or the message has no inline keyboard to edit |
| 400 | Bad Request: chat not found | Invalid or inaccessible chat_id |
| 400 | Bad Request: message not found | message_id doesn't exist in the chat |
| 403 | Forbidden: bot was blocked by the user | User blocked the bot — catch and mark user as inactive |
| 403 | Forbidden: not enough rights | Bot lacks edit permissions in a channel |
| 429 | Too Many Requests: retry after N | Flood control — check retry_after, use auto-retry plugin |
TIP
Use GramIO's auto-retry plugin to handle 429 errors automatically.
Tips & Gotchas
- Only
InlineKeyboardMarkupis supported — you cannot switch toReplyKeyboardMarkuporForceReplyusing this method. Inline keyboards are the only type that can be attached to non-private bot messages. - Omit
reply_markupto remove the keyboard. Sending the request without thereply_markupparameter removes the existing inline keyboard from the message. - This is the lightest edit method — it changes only the keyboard, leaving the message text, caption, and media untouched. Prefer this over
editMessageTextwhen only the button state needs to change. - Business messages have a 48-hour edit window. Messages sent via a business connection by another user without an inline keyboard can only be edited within 48 hours of sending.
- Inline messages return
true, notMessage. When editing viainline_message_id, the method returnstrueon success instead of the updatedMessageobject. - Ideal for wizard-style UIs. Swapping keyboards between steps is a common pattern for multi-step bots — this method handles it with minimal overhead.
See Also
- editMessageText — edit text and keyboard together
- editMessageCaption — edit media caption and keyboard together
- editMessageMedia — replace the media file
- Keyboards overview — building inline keyboards with
InlineKeyboard - InlineKeyboardMarkup — the type used for
reply_markup - Message — the type returned on success for non-inline messages
- auto-retry plugin — automatic
429retry handling