savePreparedInlineMessage
Returns: PreparedInlineMessageOfficial docs ↗
Stores a message that can be sent by a user of a Mini App. Returns a PreparedInlineMessage object.
Parameters
user_idIntegerRequiredUnique identifier of the target user that can use the prepared message
A JSON-serialized object describing the message to be sent
allow_user_chatsBooleanOptionalPass True if the message can be sent to private chats with users
allow_bot_chatsBooleanOptionalPass True if the message can be sent to private chats with bots
allow_group_chatsBooleanOptionalPass True if the message can be sent to group and supergroup chats
allow_channel_chatsBooleanOptionalPass True if the message can be sent to channel chats
Returns
On success, the PreparedInlineMessage object is returned.
GramIO Usage
Prepare an article message for a Mini App user to share in any private chat:
ts
const prepared = await bot.api.savePreparedInlineMessage({
user_id: 123456789,
result: {
type: "article",
id: "share-result-1",
title: "Check out this article",
input_message_content: {
message_text: "Here's an interesting article I found!",
},
},
allow_user_chats: true,
allow_group_chats: true,
});
// Pass prepared.id to the Mini App frontend
console.log("Prepared message ID:", prepared.id);
console.log("Expires at:", new Date(prepared.expiration_date * 1000));Prepare a photo message restricted to private chats only:
ts
const prepared = await bot.api.savePreparedInlineMessage({
user_id: 123456789,
result: {
type: "photo",
id: "photo-result-1",
photo_url: "https://example.com/promo.jpg",
thumbnail_url: "https://example.com/promo_thumb.jpg",
caption: "Our latest promotion!",
},
allow_user_chats: true,
// allow_group_chats and allow_channel_chats omitted = not allowed
});Prepare a message in a Mini App endpoint and handle expiration:
ts
// In an HTTP endpoint called from the Mini App
async function prepareMiniAppMessage(userId: number, content: string) {
const prepared = await bot.api.savePreparedInlineMessage({
user_id: userId,
result: {
type: "article",
id: `msg-${Date.now()}`,
title: "Share this",
input_message_content: {
message_text: content,
},
},
allow_user_chats: true,
allow_group_chats: true,
allow_channel_chats: true,
});
return {
id: prepared.id,
expiresAt: prepared.expiration_date, // Unix timestamp — valid for ~10 minutes
};
}Errors
| Code | Error | Cause |
|---|---|---|
| 400 | Bad Request: user not found | user_id doesn't correspond to a known Telegram user or has never interacted with the bot |
| 400 | Bad Request: RESULT_TYPE_INVALID | result.type is not a valid InlineQueryResult type |
| 400 | Bad Request: inline message is too long | Message content in input_message_content exceeds length limits |
| 400 | Bad Request: no chat type allowed | At least one of allow_user_chats, allow_bot_chats, allow_group_chats, allow_channel_chats must be true |
| 403 | Forbidden: bot was blocked by the user | User blocked the bot — they cannot use prepared messages from this bot |
| 429 | Too Many Requests: retry after N | Rate limit hit — check retry_after, use auto-retry plugin |
Tips & Gotchas
- At least one chat type must be allowed. If all four
allow_*flags are omitted orfalse, the API returns an error. Always set at least one target chat type. - Prepared messages expire in ~10 minutes. The
expiration_datefield is a Unix timestamp. Pass the prepared messageidto your Mini App frontend immediately and use it before expiry. - The
idis passed to the Mini App, notinvite_link. Your Mini App frontend callsTelegram.WebApp.switchInlineQueryor uses the prepared messageiddirectly to trigger the share dialog. resultmust be a validInlineQueryResult. Use the same result types as inanswerInlineQuery—article,photo,video,audio,document,sticker, etc.- Only the specified
user_idcan use the prepared message. Another user trying to send the same preparedidwill fail — the message is tied to one user. allow_channel_chatsrequires the user to be an admin. If the user is not a channel admin, the channel won't appear in their share dialog even with this flag set.
See Also
answerInlineQuery— Answer inline queries with the sameInlineQueryResulttypesPreparedInlineMessage— The returned object withidandexpiration_dateInlineQueryResult— Union type for all inline result variantsInlineQueryResultArticle— Most common result type for text content