copyMessage
Use this method to copy messages of any kind. Service messages, paid media messages, giveaway messages, giveaway winners messages, and invoice messages can't be copied. A quiz poll can be copied only if the value of the field correct_option_id is known to the bot. The method is analogous to the method forwardMessage, but the copied message doesn't have a link to the original message. Returns the MessageId of the sent message on success.
Parameters
chat_idIntegerStringRequiredUnique identifier for the target chat or username of the target channel (in the format
@channelusername)message_thread_idIntegerOptionalUnique identifier for the target message thread (topic) of a forum; for forum supergroups and private chats of bots with forum topic mode enabled only
direct_messages_topic_idIntegerOptionalIdentifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
from_chat_idIntegerStringRequiredUnique identifier for the chat where the original message was sent (or channel username in the format
@channelusername)message_idIntegerRequiredMessage identifier in the chat specified in from\chat\id
video_start_timestampIntegerOptionalNew start timestamp for the copied video in the message
New caption for media, 0-1024 characters after entities parsing. If not specified, the original caption is kept
parse_modeStringOptionalMode for parsing entities in the new caption. See formatting options for more details.
A JSON-serialized list of special entities that appear in the new caption, which can be specified instead of parse\_mode
show_caption_above_mediaBooleanOptionalPass True, if the caption must be shown above the message media. Ignored if a new caption isn't specified.
disable_notificationBooleanOptionalSends the message silently. Users will receive a notification with no sound.
protect_contentBooleanOptionalProtects the contents of the sent message from forwarding and saving
allow_paid_broadcastBooleanOptionalPass True to allow up to 1000 messages per second, ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
message_effect_idStringOptionalUnique identifier of the message effect to be added to the message; only available when copying to private chats
A JSON-serialized object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
Description of the message to reply to
reply_markupInlineKeyboardMarkupReplyKeyboardMarkupReplyKeyboardRemoveForceReplyOptional⌨️ KeyboardsAdditional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user
Returns
On success, the MessageId object is returned.
GramIO Usage
ts
// Copy a message from one chat to another (no forwarding attribution)
const result = await bot.api.copyMessage({
chat_id: -1001234567890,
from_chat_id: "@sourcechannel",
message_id: 42,
});
console.log("Copied message ID:", result.message_id);ts
// Copy a message from context (e.g., relay a user message to an admin group)
bot.on("message", async (ctx) => {
await bot.api.copyMessage({
chat_id: -1009876543210, // admin group
from_chat_id: ctx.chatId,
message_id: ctx.id,
});
});ts
// Copy a media message and replace its caption using GramIO format helpers
await bot.api.copyMessage({
chat_id: -1001234567890,
from_chat_id: "@sourcechannel",
message_id: 100,
caption: format`${bold("New Title")} — ${italic("Updated caption")}`,
});ts
// Copy a message and attach an inline keyboard
await bot.api.copyMessage({
chat_id: -1001234567890,
from_chat_id: "@sourcechannel",
message_id: 55,
reply_markup: new InlineKeyboard().text("Open original", "open_55"),
});ts
// Silent copy (no notification sound) with content protection
await bot.api.copyMessage({
chat_id: -1001234567890,
from_chat_id: -1009876543210,
message_id: 77,
disable_notification: true,
protect_content: true,
});Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: chat not found | chat_id or from_chat_id is invalid or the bot has no access |
| 400 | Bad Request: message not found | message_id does not exist in from_chat_id |
| 400 | Bad Request: can't copy this type of message | Attempted to copy a service message, invoice, paid media, giveaway, or giveaway winners message |
| 400 | Bad Request: message is protected | The source message has protect_content enabled and cannot be copied |
| 400 | Bad Request: wrong quiz correct_option_id | Quiz poll copied without correct correct_option_id being known to the bot |
| 400 | Bad Request: caption too long | caption exceeds 1024 characters |
| 403 | Forbidden: bot is not a member of the channel chat | Bot is not in the target channel |
| 429 | Too Many Requests: retry after N | Rate limit hit — check retry_after, use auto-retry plugin |
TIP
Use GramIO's auto-retry plugin to handle 429 errors automatically when broadcasting messages to many users.
Tips & Gotchas
- No forwarding attribution. Unlike
forwardMessage, the copied message shows no "Forwarded from" header. Use this when you want to relay content without revealing the source. - Caption override is optional. If you omit
caption, the original caption is preserved. Pass an empty string""to remove the caption entirely. parse_modeandcaption_entitiesare mutually exclusive. GramIO'sformathelper always producescaption_entities, so never passparse_modealongside it.- Service messages cannot be copied. This includes join/leave notifications, pinned message notices, invoice messages, and others. Copy only regular text/media messages.
- Quiz polls need
correct_option_id. A bot can only copy a quiz poll if it knows the correct option. If the bot never saw the answer, it cannot copy a quiz. protect_contenton source blocks copying. If the original message has content protection,copyMessagewill fail with a 400 error.- For bulk copying, use
copyMessages. It supports 1–100 message IDs in a single call and preserves media album grouping.
See Also
copyMessages— copy multiple messages in one call, preserving album groupsforwardMessage— forward a message with source attributionforwardMessages— forward multiple messages at onceMessageId— the returned type- Formatting guide — using
format,bold,italicfor captions - Keyboards guide — adding
reply_markupto copied messages - Auto-retry plugin — handle rate limits automatically