From 9c363f470ab74aa0dfeaa42f78eeb41862dfdd35 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Tue, 21 Jul 2026 22:52:20 +0100 Subject: [PATCH] chore(api): regenerate from Telegram Bot API v10.2 Snapshot taken 2026-07-21. Notable shape change: ReplyParameters.MessageID becomes optional (*int64) because Bot API 10.2 allows a reply to target ephemeral_message_id instead. This breaks callers that set MessageID by value, so examples/echo passes the address now. New surface includes the ephemeral message methods, sendRichMessage with InputRichMessageMedia, and the Community service messages. --- api/enums.gen.go | 40 + api/methods.gen.go | 343 +- api/methods_gen_test.go | 769 + api/types.gen.go | 856 +- docs/reference/api.md | 3217 ++-- examples/echo/handlers.go | 2 +- internal/spec/api.json | 2071 +- testdata/html/latest.html | 2 +- testdata/html/snapshot_2026-07-21.html | 23115 +++++++++++++++++++++++ 9 files changed, 29069 insertions(+), 1346 deletions(-) create mode 100644 testdata/html/snapshot_2026-07-21.html diff --git a/api/enums.gen.go b/api/enums.gen.go index d5022a6..e5db402 100644 --- a/api/enums.gen.go +++ b/api/enums.gen.go @@ -33,6 +33,14 @@ const ( BotCommandScopeTypeChatMember BotCommandScopeType = "chat_member" ) +type BotSubscriptionUpdatedState string + +const ( + BotSubscriptionUpdatedStateCanceled BotSubscriptionUpdatedState = "canceled" + BotSubscriptionUpdatedStateActive BotSubscriptionUpdatedState = "active" + BotSubscriptionUpdatedStateFailed BotSubscriptionUpdatedState = "failed" +) + type ChatBoostSourceKind string const ( @@ -133,6 +141,12 @@ const ( InputMediaTypeVideo InputMediaType = "video" ) +type InputMediaVoiceNoteType string + +const ( + InputMediaVoiceNoteTypeVoiceNote InputMediaVoiceNoteType = "voice_note" +) + type InputPaidMediaType string const ( @@ -174,6 +188,32 @@ const ( InputProfilePhotoTypeAnimated InputProfilePhotoType = "animated" ) +type InputRichBlockType string + +const ( + InputRichBlockTypeParagraph InputRichBlockType = "paragraph" + InputRichBlockTypeHeading InputRichBlockType = "heading" + InputRichBlockTypePre InputRichBlockType = "pre" + InputRichBlockTypeFooter InputRichBlockType = "footer" + InputRichBlockTypeDivider InputRichBlockType = "divider" + InputRichBlockTypeMathematicalExpression InputRichBlockType = "mathematical_expression" + InputRichBlockTypeAnchor InputRichBlockType = "anchor" + InputRichBlockTypeList InputRichBlockType = "list" + InputRichBlockTypeBlockquote InputRichBlockType = "blockquote" + InputRichBlockTypePullquote InputRichBlockType = "pullquote" + InputRichBlockTypeCollage InputRichBlockType = "collage" + InputRichBlockTypeSlideshow InputRichBlockType = "slideshow" + InputRichBlockTypeTable InputRichBlockType = "table" + InputRichBlockTypeDetails InputRichBlockType = "details" + InputRichBlockTypeMap InputRichBlockType = "map" + InputRichBlockTypeAnimation InputRichBlockType = "animation" + InputRichBlockTypeAudio InputRichBlockType = "audio" + InputRichBlockTypePhoto InputRichBlockType = "photo" + InputRichBlockTypeVideo InputRichBlockType = "video" + InputRichBlockTypeVoiceNote InputRichBlockType = "voice_note" + InputRichBlockTypeThinking InputRichBlockType = "thinking" +) + type InputStickerFormat string const ( diff --git a/api/methods.gen.go b/api/methods.gen.go index 6e70893..4b501c6 100644 --- a/api/methods.gen.go +++ b/api/methods.gen.go @@ -195,6 +195,10 @@ type SendMessageParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Text of the message to be sent, 1-4096 characters after entities parsing Text string `json:"text"` // Mode for parsing entities in the message text. See formatting options for more details. @@ -261,7 +265,7 @@ func ForwardMessage(ctx context.Context, b *client.Bot, p *ForwardMessageParams) // ForwardMessagesParams is the parameter set for ForwardMessages. // -// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an array of MessageId of the sent messages is returned. +// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an Array of MessageId of the sent messages is returned. type ForwardMessagesParams struct { // Unique identifier for the target chat or username of the target bot, supergroup or channel in the format @username ChatID ChatID `json:"chat_id"` @@ -281,14 +285,14 @@ type ForwardMessagesParams struct { // ForwardMessages calls the forwardMessages Telegram Bot API method. // -// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an array of MessageId of the sent messages is returned. +// Use this method to forward multiple messages of any kind. If some of the specified messages can't be found or forwarded, they are skipped. Service messages and messages with protected content can't be forwarded. Album grouping is kept for forwarded messages. On success, an Array of MessageId of the sent messages is returned. func ForwardMessages(ctx context.Context, b *client.Bot, p *ForwardMessagesParams) ([]MessageId, error) { return client.Call[*ForwardMessagesParams, []MessageId](ctx, b, "forwardMessages", p) } // CopyMessageParams is the parameter set for 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. +// 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_ids 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. type CopyMessageParams struct { // Unique identifier for the target chat or username of the target bot, supergroup or channel in the format @username ChatID ChatID `json:"chat_id"` @@ -308,7 +312,7 @@ type CopyMessageParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the new caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media. Ignored if a new caption isn't specified. + // Pass True if the caption must be shown above the message media. Ignored if a new caption isn't specified. ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Sends the message silently. Users will receive a notification with no sound. DisableNotification *bool `json:"disable_notification,omitempty"` @@ -328,14 +332,14 @@ type CopyMessageParams struct { // CopyMessage calls the copyMessage Telegram Bot API method. // -// 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. +// 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_ids 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. func CopyMessage(ctx context.Context, b *client.Bot, p *CopyMessageParams) (*MessageId, error) { return client.Call[*CopyMessageParams, *MessageId](ctx, b, "copyMessage", p) } // CopyMessagesParams is the parameter set for CopyMessages. // -// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. 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 forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array of MessageId of the sent messages is returned. +// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. 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_ids is known to the bot. The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an Array of MessageId of the sent messages is returned. type CopyMessagesParams struct { // Unique identifier for the target chat or username of the target bot, supergroup or channel in the format @username ChatID ChatID `json:"chat_id"` @@ -357,7 +361,7 @@ type CopyMessagesParams struct { // CopyMessages calls the copyMessages Telegram Bot API method. // -// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. 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 forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an array of MessageId of the sent messages is returned. +// Use this method to copy messages of any kind. If some of the specified messages can't be found or copied, they are skipped. 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_ids is known to the bot. The method is analogous to the method forwardMessages, but the copied messages don't have a link to the original message. Album grouping is kept for copied messages. On success, an Array of MessageId of the sent messages is returned. func CopyMessages(ctx context.Context, b *client.Bot, p *CopyMessagesParams) ([]MessageId, error) { return client.Call[*CopyMessagesParams, []MessageId](ctx, b, "copyMessages", p) } @@ -374,6 +378,10 @@ type SendPhotoParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Photo to send. Pass a file_id as String to send a photo that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a photo from the Internet, or upload a new photo using multipart/form-data. The photo must be at most 10 MB in size. The photo's width and height must not exceed 10000 in total. Width and height ratio must be at most 20. More information on Sending Files » Photo *InputFile `json:"photo"` // Photo caption (may also be used when resending photos by file_id), 0-1024 characters after entities parsing @@ -382,7 +390,7 @@ type SendPhotoParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media + // Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Pass True if the photo needs to be covered with a spoiler animation HasSpoiler *bool `json:"has_spoiler,omitempty"` @@ -423,6 +431,12 @@ func (p *SendPhotoParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Caption != "" { out["caption"] = p.Caption } @@ -502,6 +516,10 @@ type SendLivePhotoParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Live photo video to send. The video must be no longer than 10 seconds and must not exceed 10 MB in size. Pass a file_id as String to send a video that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data. More information on Sending Files ». Sending live photos by a URL is currently unsupported. LivePhoto *InputFile `json:"live_photo"` // The static photo to send. Pass a file_id as String to send a photo that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data. More information on Sending Files ». Sending live photos by a URL is currently unsupported. @@ -512,7 +530,7 @@ type SendLivePhotoParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media + // Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Pass True if the video needs to be covered with a spoiler animation HasSpoiler *bool `json:"has_spoiler,omitempty"` @@ -556,6 +574,12 @@ func (p *SendLivePhotoParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Caption != "" { out["caption"] = p.Caption } @@ -643,6 +667,10 @@ type SendAudioParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Audio file to send. Pass a file_id as String to send an audio file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an audio file from the Internet, or upload a new one using multipart/form-data. More information on Sending Files » Audio *InputFile `json:"audio"` // Audio caption, 0-1024 characters after entities parsing @@ -699,6 +727,12 @@ func (p *SendAudioParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Caption != "" { out["caption"] = p.Caption } @@ -789,6 +823,10 @@ type SendDocumentParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // File to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. More information on Sending Files » Document *InputFile `json:"document"` // Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass “attach://” if the thumbnail was uploaded using multipart/form-data under . More information on Sending Files » @@ -841,6 +879,12 @@ func (p *SendDocumentParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Caption != "" { out["caption"] = p.Caption } @@ -924,6 +968,10 @@ type SendVideoParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Video to send. Pass a file_id as String to send a video that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a video from the Internet, or upload a new video using multipart/form-data. More information on Sending Files » Video *InputFile `json:"video"` // Duration of sent video in seconds @@ -944,7 +992,7 @@ type SendVideoParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media + // Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Pass True if the video needs to be covered with a spoiler animation HasSpoiler *bool `json:"has_spoiler,omitempty"` @@ -993,6 +1041,12 @@ func (p *SendVideoParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Duration != nil { out["duration"] = strconv.FormatInt(*p.Duration, 10) } @@ -1101,6 +1155,10 @@ type SendAnimationParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Animation to send. Pass a file_id as String to send an animation that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get an animation from the Internet, or upload a new animation using multipart/form-data. More information on Sending Files » Animation *InputFile `json:"animation"` // Duration of sent animation in seconds @@ -1117,7 +1175,7 @@ type SendAnimationParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media + // Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Pass True if the animation needs to be covered with a spoiler animation HasSpoiler *bool `json:"has_spoiler,omitempty"` @@ -1161,6 +1219,12 @@ func (p *SendAnimationParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Duration != nil { out["duration"] = strconv.FormatInt(*p.Duration, 10) } @@ -1256,6 +1320,10 @@ type SendVoiceParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Audio file to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a file from the Internet, or upload a new one using multipart/form-data. More information on Sending Files » Voice *InputFile `json:"voice"` // Voice message caption, 0-1024 characters after entities parsing @@ -1303,6 +1371,12 @@ func (p *SendVoiceParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Caption != "" { out["caption"] = p.Caption } @@ -1379,6 +1453,10 @@ type SendVideoNoteParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Video note to send. Pass a file_id as String to send a video note that exists on the Telegram servers (recommended) or upload a new video using multipart/form-data. More information on Sending Files ». Sending video notes by a URL is currently unsupported. VideoNote *InputFile `json:"video_note"` // Duration of sent video in seconds @@ -1427,6 +1505,12 @@ func (p *SendVideoNoteParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Duration != nil { out["duration"] = strconv.FormatInt(*p.Duration, 10) } @@ -1504,7 +1588,7 @@ type SendPaidMediaParams struct { DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` // The number of Telegram Stars that must be paid to buy access to the media; 1-25000 StarCount int64 `json:"star_count"` - // A JSON-serialized array describing the media to be sent; up to 10 items + // A JSON-serialized Array describing the media to be sent; up to 10 items Media []InputPaidMedia `json:"media"` // Bot-defined paid media payload, 0-128 bytes. This will not be displayed to the user, use it for your internal processes. Payload string `json:"payload,omitempty"` @@ -1514,7 +1598,7 @@ type SendPaidMediaParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media + // Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Sends the message silently. Users will receive a notification with no sound. DisableNotification *bool `json:"disable_notification,omitempty"` @@ -1611,7 +1695,7 @@ func SendPaidMedia(ctx context.Context, b *client.Bot, p *SendPaidMediaParams) ( // SendMediaGroupParams is the parameter set for SendMediaGroup. // -// Use this method to send a group of photos, live photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an array of Message objects that were sent is returned. +// Use this method to send a group of photos, live photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an Array of Message objects that were sent is returned. type SendMediaGroupParams struct { // Unique identifier of the business connection on behalf of which the message will be sent BusinessConnectionID string `json:"business_connection_id,omitempty"` @@ -1621,7 +1705,7 @@ type SendMediaGroupParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the messages will be sent; required if the messages are sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` - // A JSON-serialized array describing messages to be sent, must include 2-10 items + // A JSON-serialized Array describing messages to be sent, must include 2-10 items Media []any `json:"media"` // Sends messages silently. Users will receive a notification with no sound. DisableNotification *bool `json:"disable_notification,omitempty"` @@ -1684,7 +1768,7 @@ func (p *SendMediaGroupParams) MultipartFiles() []client.MultipartFile { // SendMediaGroup calls the sendMediaGroup Telegram Bot API method. // -// Use this method to send a group of photos, live photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an array of Message objects that were sent is returned. +// Use this method to send a group of photos, live photos, videos, documents or audios as an album. Documents and audio files can be only grouped in an album with messages of the same type. On success, an Array of Message objects that were sent is returned. func SendMediaGroup(ctx context.Context, b *client.Bot, p *SendMediaGroupParams) ([]Message, error) { return client.Call[*SendMediaGroupParams, []Message](ctx, b, "sendMediaGroup", p) } @@ -1701,13 +1785,17 @@ type SendLocationParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Latitude of the location Latitude float64 `json:"latitude"` // Longitude of the location Longitude float64 `json:"longitude"` // The radius of uncertainty for the location, measured in meters; 0-1500 HorizontalAccuracy *float64 `json:"horizontal_accuracy,omitempty"` - // Period in seconds during which the location will be updated (see Live Locations, should be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely + // Period in seconds during which the location will be updated (see Live Locations), must be between 60 and 86400, or 0x7FFFFFFF for live locations that can be edited indefinitely. Must be 0 for ephemeral messages. LivePeriod *int64 `json:"live_period,omitempty"` // For live locations, a direction in which the user is moving, in degrees. Must be between 1 and 360 if specified. Heading *int64 `json:"heading,omitempty"` @@ -1748,6 +1836,10 @@ type SendVenueParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Latitude of the venue Latitude float64 `json:"latitude"` // Longitude of the venue @@ -1799,6 +1891,10 @@ type SendContactParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Contact's phone number PhoneNumber string `json:"phone_number"` // Contact's first name @@ -1852,17 +1948,17 @@ type SendPollParams struct { IsAnonymous *bool `json:"is_anonymous,omitempty"` // Poll type, “quiz” or “regular”, defaults to “regular” Type string `json:"type,omitempty"` - // Pass True, if the poll allows multiple answers, defaults to False + // Pass True if the poll allows multiple answers, defaults to False AllowsMultipleAnswers *bool `json:"allows_multiple_answers,omitempty"` - // Pass True, if the poll allows to change chosen answer options, defaults to False for quizzes and to True for regular polls + // Pass True if the poll allows to change chosen answer options, defaults to False for quizzes and to True for regular polls AllowsRevoting *bool `json:"allows_revoting,omitempty"` - // Pass True, if the poll options must be shown in random order + // Pass True if the poll options must be shown in random order ShuffleOptions *bool `json:"shuffle_options,omitempty"` - // Pass True, if answer options can be added to the poll after creation; not supported for anonymous polls and quizzes + // Pass True if answer options can be added to the poll after creation; not supported for anonymous polls and quizzes AllowAddingOptions *bool `json:"allow_adding_options,omitempty"` - // Pass True, if poll results must be shown only after the poll closes + // Pass True if poll results must be shown only after the poll closes HideResultsUntilCloses *bool `json:"hide_results_until_closes,omitempty"` - // Pass True, if voting is limited to users who have been members of the chat where the poll is being sent for more than 24 hours; for channel chats only + // Pass True if voting is limited to users who have been members of the chat where the poll is being sent for more than 24 hours; for channel chats only MembersOnly *bool `json:"members_only,omitempty"` // A JSON-serialized list of 0-12 two-letter ISO 3166-1 alpha-2 country codes indicating the countries from which users can vote in the poll; for channel chats only. Use “FT” as a country code to allow users with anonymous numbers to vote. If omitted or empty, then users from any country can participate in the poll. CountryCodes []string `json:"country_codes,omitempty"` @@ -1985,7 +2081,7 @@ type SendMessageDraftParams struct { ChatID int64 `json:"chat_id"` // Unique identifier for the target message thread MessageThreadID *int64 `json:"message_thread_id,omitempty"` - // Unique identifier of the message draft; must be non-zero. Changes of drafts with the same identifier are animated. + // Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated. DraftID int64 `json:"draft_id"` // Text of the message to be sent, 0-4096 characters after entities parsing. Pass an empty text to show a “Thinking…” placeholder. Text string `json:"text,omitempty"` @@ -2502,17 +2598,17 @@ func AnswerChatJoinRequestQuery(ctx context.Context, b *client.Bot, p *AnswerCha // SendChatJoinRequestWebAppParams is the parameter set for SendChatJoinRequestWebApp. // -// Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Returns True on success. +// Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Call answerChatJoinRequestQuery to resolve the join request query based on the user interaction with the Mini App. Returns True on success. type SendChatJoinRequestWebAppParams struct { // Unique identifier of the join request query ChatJoinRequestQueryID string `json:"chat_join_request_query_id"` - // The URL of the Mini App to be opened + // An HTTPS URL of a Web App to be opened with additional data as specified in Initializing Web Apps WebAppURL string `json:"web_app_url"` } // SendChatJoinRequestWebApp calls the sendChatJoinRequestWebApp Telegram Bot API method. // -// Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Returns True on success. +// Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Call answerChatJoinRequestQuery to resolve the join request query based on the user interaction with the Mini App. Returns True on success. func SendChatJoinRequestWebApp(ctx context.Context, b *client.Bot, p *SendChatJoinRequestWebAppParams) (bool, error) { return client.Call[*SendChatJoinRequestWebAppParams, bool](ctx, b, "sendChatJoinRequestWebApp", p) } @@ -2731,7 +2827,7 @@ func GetChatAdministrators(ctx context.Context, b *client.Bot, p *GetChatAdminis // GetChatMemberCountParams is the parameter set for GetChatMemberCount. // -// Use this method to get the number of members in a chat. Returns Int on success. +// Use this method to get the number of members in a chat. Returns Integer on success. type GetChatMemberCountParams struct { // Unique identifier for the target chat or username of the target supergroup or channel in the format @username ChatID ChatID `json:"chat_id"` @@ -2739,7 +2835,7 @@ type GetChatMemberCountParams struct { // GetChatMemberCount calls the getChatMemberCount Telegram Bot API method. // -// Use this method to get the number of members in a chat. Returns Int on success. +// Use this method to get the number of members in a chat. Returns Integer on success. func GetChatMemberCount(ctx context.Context, b *client.Bot, p *GetChatMemberCountParams) (int64, error) { return client.Call[*GetChatMemberCountParams, int64](ctx, b, "getChatMemberCount", p) } @@ -2767,7 +2863,7 @@ func GetChatMember(ctx context.Context, b *client.Bot, p *GetChatMemberParams) ( // GetUserPersonalChatMessagesParams is the parameter set for GetUserPersonalChatMessages. // -// Use this method to get the last messages from the personal chat (i.e., the chat currently added to their profile) of a given user. On success, an array of Message objects is returned. +// Use this method to get the last messages from the personal chat (i.e., the chat currently added to their profile) of a given user. On success, an Array of Message objects is returned. type GetUserPersonalChatMessagesParams struct { // Unique identifier for the target user UserID int64 `json:"user_id"` @@ -2777,7 +2873,7 @@ type GetUserPersonalChatMessagesParams struct { // GetUserPersonalChatMessages calls the getUserPersonalChatMessages Telegram Bot API method. // -// Use this method to get the last messages from the personal chat (i.e., the chat currently added to their profile) of a given user. On success, an array of Message objects is returned. +// Use this method to get the last messages from the personal chat (i.e., the chat currently added to their profile) of a given user. On success, an Array of Message objects is returned. func GetUserPersonalChatMessages(ctx context.Context, b *client.Bot, p *GetUserPersonalChatMessagesParams) ([]Message, error) { return client.Call[*GetUserPersonalChatMessagesParams, []Message](ctx, b, "getUserPersonalChatMessages", p) } @@ -3038,7 +3134,7 @@ type AnswerCallbackQueryParams struct { CallbackQueryID string `json:"callback_query_id"` // Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters. Text string `json:"text,omitempty"` - // If True, an alert will be shown by the client instead of a notification at the top of the chat screen. Defaults to false. + // If True, an alert will be shown by the client instead of a notification at the top of the chat screen. Defaults to False. ShowAlert *bool `json:"show_alert,omitempty"` // URL that will be opened by the user's client. If you have created a Game and accepted the conditions via @BotFather, specify the URL that opens your game - note that this will only work if the query comes from a callback_game button.Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter. URL string `json:"url,omitempty"` @@ -3154,9 +3250,9 @@ func GetManagedBotAccessSettings(ctx context.Context, b *client.Bot, p *GetManag type SetManagedBotAccessSettingsParams struct { // User identifier of the managed bot whose access settings will be changed UserID int64 `json:"user_id"` - // Pass True, if only selected users can access the bot. The bot's owner can always access it. + // Pass True if only selected users can access the bot. The bot's owner can always access it. IsAccessRestricted bool `json:"is_access_restricted"` - // A JSON-serialized list of up to 10 identifiers of users who will have access to the bot in addition to its owner. Ignored if is_access_restricted is false. + // A JSON-serialized list of up to 10 identifiers of users who will have access to the bot in addition to its owner. Ignored if is_access_restricted is False. AddedUserIds []int64 `json:"added_user_ids,omitempty"` } @@ -3672,7 +3768,7 @@ func RemoveBusinessAccountProfilePhoto(ctx context.Context, b *client.Bot, p *Re type SetBusinessAccountGiftSettingsParams struct { // Unique identifier of the business connection BusinessConnectionID string `json:"business_connection_id"` - // Pass True, if a button for sending a gift to the user or by the business account must always be shown in the input field + // Pass True if a button for sending a gift to the user or by the business account must always be shown in the input field ShowGiftButton bool `json:"show_gift_button"` // Types of gifts accepted by the business account AcceptedGiftTypes AcceptedGiftTypes `json:"accepted_gift_types"` @@ -4056,7 +4152,7 @@ type EditMessageTextParams struct { Entities []MessageEntity `json:"entities,omitempty"` // Link preview generation options for the message LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` - // New rich content of the message; required if text isn't specified + // New rich content of the message; required if text isn't specified. Direct upload of new files isn't supported when an inline message is edited. RichMessage *InputRichMessage `json:"rich_message,omitempty"` // A JSON-serialized object for an inline keyboard ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` @@ -4087,7 +4183,7 @@ type EditMessageCaptionParams struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Pass True, if the caption must be shown above the message media. Supported only for animation, photo and video messages. + // Pass True if the caption must be shown above the message media. Supported only for animation, photo and video messages. ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // A JSON-serialized object for an inline keyboard ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` @@ -4112,7 +4208,7 @@ type EditMessageMediaParams struct { MessageID *int64 `json:"message_id,omitempty"` // Required if chat_id and message_id are not specified. Identifier of the inline message. InlineMessageID string `json:"inline_message_id,omitempty"` - // A JSON-serialized object for a new media content of the message + // A JSON-serialized object for the new media content of the message Media InputMedia `json:"media"` // A JSON-serialized object for a new inline keyboard ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` @@ -4287,6 +4383,134 @@ func StopPoll(ctx context.Context, b *client.Bot, p *StopPollParams) (*Poll, err return client.Call[*StopPollParams, *Poll](ctx, b, "stopPoll", p) } +// EditEphemeralMessageTextParams is the parameter set for EditEphemeralMessageText. +// +// Use this method to edit an ephemeral text message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +type EditEphemeralMessageTextParams struct { + // Unique identifier for the target chat or username of the target supergroup in the format @username + ChatID ChatID `json:"chat_id"` + // Identifier of the user who received the message + ReceiverUserID int64 `json:"receiver_user_id"` + // Identifier of the ephemeral message to edit + EphemeralMessageID int64 `json:"ephemeral_message_id"` + // New text of the message, 1-4096 characters after entity parsing + Text string `json:"text"` + // Mode for parsing entities in the message text. See formatting options for more details. + ParseMode ParseMode `json:"parse_mode,omitempty"` + // A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode + Entities []MessageEntity `json:"entities,omitempty"` + // Link preview generation options for the message + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + // A JSON-serialized object for an inline keyboard + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// EditEphemeralMessageText calls the editEphemeralMessageText Telegram Bot API method. +// +// Use this method to edit an ephemeral text message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +func EditEphemeralMessageText(ctx context.Context, b *client.Bot, p *EditEphemeralMessageTextParams) (bool, error) { + return client.Call[*EditEphemeralMessageTextParams, bool](ctx, b, "editEphemeralMessageText", p) +} + +// EditEphemeralMessageMediaParams is the parameter set for EditEphemeralMessageMedia. +// +// Use this method to edit the media of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +type EditEphemeralMessageMediaParams struct { + // Unique identifier for the target chat or username of the target supergroup in the format @username + ChatID ChatID `json:"chat_id"` + // Identifier of the user who received the message + ReceiverUserID int64 `json:"receiver_user_id"` + // Identifier of the ephemeral message to edit + EphemeralMessageID int64 `json:"ephemeral_message_id"` + // A JSON-serialized object for the new media content of the message. A new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. + Media InputMedia `json:"media"` + // A JSON-serialized object for an inline keyboard + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// HasFile reports whether a multipart upload is required. +func (p *EditEphemeralMessageMediaParams) HasFile() bool { + return false +} + +// MultipartFields returns the non-file fields used in the multipart body. +func (p *EditEphemeralMessageMediaParams) MultipartFields() map[string]string { + out := map[string]string{} + out["chat_id"] = p.ChatID.String() + out["receiver_user_id"] = strconv.FormatInt(p.ReceiverUserID, 10) + out["ephemeral_message_id"] = strconv.FormatInt(p.EphemeralMessageID, 10) + if b, _ := json.Marshal(p.Media); len(b) > 0 { + out["media"] = string(b) + } + if p.ReplyMarkup != nil { + if b, _ := json.Marshal(p.ReplyMarkup); len(b) > 0 { + out["reply_markup"] = string(b) + } + } + return out +} + +// MultipartFiles returns the file parts. +func (p *EditEphemeralMessageMediaParams) MultipartFiles() []client.MultipartFile { + var files []client.MultipartFile + return files +} + +// EditEphemeralMessageMedia calls the editEphemeralMessageMedia Telegram Bot API method. +// +// Use this method to edit the media of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +func EditEphemeralMessageMedia(ctx context.Context, b *client.Bot, p *EditEphemeralMessageMediaParams) (bool, error) { + return client.Call[*EditEphemeralMessageMediaParams, bool](ctx, b, "editEphemeralMessageMedia", p) +} + +// EditEphemeralMessageCaptionParams is the parameter set for EditEphemeralMessageCaption. +// +// Use this method to edit the caption of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +type EditEphemeralMessageCaptionParams struct { + // Unique identifier for the target chat or username of the target supergroup in the format @username + ChatID ChatID `json:"chat_id"` + // Identifier of the user who received the message + ReceiverUserID int64 `json:"receiver_user_id"` + // Identifier of the ephemeral message to edit + EphemeralMessageID int64 `json:"ephemeral_message_id"` + // New caption of the message, 0-1024 characters after entities parsing + Caption string `json:"caption,omitempty"` + // Mode for parsing entities in the message caption. See formatting options for more details. + ParseMode ParseMode `json:"parse_mode,omitempty"` + // A JSON-serialized list of special entities that appear in the caption, which can be specified instead of parse_mode + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // A JSON-serialized object for an inline keyboard + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// EditEphemeralMessageCaption calls the editEphemeralMessageCaption Telegram Bot API method. +// +// Use this method to edit the caption of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +func EditEphemeralMessageCaption(ctx context.Context, b *client.Bot, p *EditEphemeralMessageCaptionParams) (bool, error) { + return client.Call[*EditEphemeralMessageCaptionParams, bool](ctx, b, "editEphemeralMessageCaption", p) +} + +// EditEphemeralMessageReplyMarkupParams is the parameter set for EditEphemeralMessageReplyMarkup. +// +// Use this method to edit only the reply markup of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +type EditEphemeralMessageReplyMarkupParams struct { + // Unique identifier for the target chat or username of the target supergroup in the format @username + ChatID ChatID `json:"chat_id"` + // Identifier of the user who received the message + ReceiverUserID int64 `json:"receiver_user_id"` + // Identifier of the ephemeral message to edit + EphemeralMessageID int64 `json:"ephemeral_message_id"` + // A JSON-serialized object for an inline keyboard + ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` +} + +// EditEphemeralMessageReplyMarkup calls the editEphemeralMessageReplyMarkup Telegram Bot API method. +// +// Use this method to edit only the reply markup of an ephemeral message. Note that it is not guaranteed that the user will receive the message edit event, especially if they are offline. On success, True is returned. +func EditEphemeralMessageReplyMarkup(ctx context.Context, b *client.Bot, p *EditEphemeralMessageReplyMarkupParams) (bool, error) { + return client.Call[*EditEphemeralMessageReplyMarkupParams, bool](ctx, b, "editEphemeralMessageReplyMarkup", p) +} + // ApproveSuggestedPostParams is the parameter set for ApproveSuggestedPost. // // Use this method to approve a suggested post in a direct messages chat. The bot must have the 'can_post_messages' administrator right in the corresponding channel chat. Returns True on success. @@ -4359,6 +4583,25 @@ func DeleteMessages(ctx context.Context, b *client.Bot, p *DeleteMessagesParams) return client.Call[*DeleteMessagesParams, bool](ctx, b, "deleteMessages", p) } +// DeleteEphemeralMessageParams is the parameter set for DeleteEphemeralMessage. +// +// Use this method to delete an ephemeral message. Note that it is not guaranteed that the user will receive the message deletion event, especially if they are offline. Returns True on success. +type DeleteEphemeralMessageParams struct { + // Unique identifier for the target chat or username of the target supergroup in the format @username + ChatID ChatID `json:"chat_id"` + // Identifier of the user who received the message + ReceiverUserID int64 `json:"receiver_user_id"` + // Identifier of the ephemeral message to delete + EphemeralMessageID int64 `json:"ephemeral_message_id"` +} + +// DeleteEphemeralMessage calls the deleteEphemeralMessage Telegram Bot API method. +// +// Use this method to delete an ephemeral message. Note that it is not guaranteed that the user will receive the message deletion event, especially if they are offline. Returns True on success. +func DeleteEphemeralMessage(ctx context.Context, b *client.Bot, p *DeleteEphemeralMessageParams) (bool, error) { + return client.Call[*DeleteEphemeralMessageParams, bool](ctx, b, "deleteEphemeralMessage", p) +} + // DeleteMessageReactionParams is the parameter set for DeleteMessageReaction. // // Use this method to remove a reaction from a message in a group or a supergroup chat. The bot must have the 'can_delete_messages' administrator right in the chat. Returns True on success. @@ -4411,6 +4654,10 @@ type SendStickerParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // For outgoing ephemeral messages, unique identifier of the user who will receive the message; for group and supergroup chats only. It is not guaranteed that the user will receive the message, especially if they are offline. See ephemeral message sending for more details. + ReceiverUserID *int64 `json:"receiver_user_id,omitempty"` + // For outgoing ephemeral messages, identifier of the callback query which triggered the message if any + CallbackQueryID string `json:"callback_query_id,omitempty"` // Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP sticker from the Internet, or upload a new .WEBP, .TGS, or .WEBM sticker using multipart/form-data. More information on Sending Files ». Video and animated stickers can't be sent via an HTTP URL. Sticker *InputFile `json:"sticker"` // Emoji associated with the sticker; only for just uploaded stickers @@ -4452,6 +4699,12 @@ func (p *SendStickerParams) MultipartFields() map[string]string { if p.DirectMessagesTopicID != nil { out["direct_messages_topic_id"] = strconv.FormatInt(*p.DirectMessagesTopicID, 10) } + if p.ReceiverUserID != nil { + out["receiver_user_id"] = strconv.FormatInt(*p.ReceiverUserID, 10) + } + if p.CallbackQueryID != "" { + out["callback_query_id"] = p.CallbackQueryID + } if p.Emoji != "" { out["emoji"] = p.Emoji } @@ -4835,7 +5088,7 @@ func DeleteStickerSet(ctx context.Context, b *client.Bot, p *DeleteStickerSetPar // // Use this method to send rich messages. If the message contains a block with a media element, then the bot must have the right to send the media to the chat. On success, the sent Message is returned. type SendRichMessageParams struct { - // Unique identifier of the business connection on behalf of which the message will be sent + // Unique identifier of the business connection on behalf of which the message will be sent. Bot can send rich messages on behalf of a business account only if the corresponding user can send rich messages. BusinessConnectionID string `json:"business_connection_id,omitempty"` // Unique identifier for the target chat or username of the target bot, supergroup or channel in the format @username ChatID ChatID `json:"chat_id"` @@ -4878,7 +5131,7 @@ type SendRichMessageDraftParams struct { MessageThreadID *int64 `json:"message_thread_id,omitempty"` // Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated. DraftID int64 `json:"draft_id"` - // The partial message to be streamed + // The partial message to be streamed. Direct upload of new files isn't supported. RichMessage InputRichMessage `json:"rich_message"` } @@ -4895,7 +5148,7 @@ func SendRichMessageDraft(ctx context.Context, b *client.Bot, p *SendRichMessage type AnswerInlineQueryParams struct { // Unique identifier for the answered query InlineQueryID string `json:"inline_query_id"` - // A JSON-serialized array of results for the inline query + // A JSON-serialized Array of results for the inline query Results []InlineQueryResult `json:"results"` // The maximum amount of time in seconds that the result of the inline query may be cached on the server. Defaults to 300. CacheTime *int64 `json:"cache_time,omitempty"` @@ -4938,7 +5191,7 @@ type SendInvoiceParams struct { Prices []LabeledPrice `json:"prices"` // The maximum accepted amount for tips in the smallest units of the currency (integer, not float/double). For example, for a maximum tip of US$ 1.45 pass max_tip_amount = 145. See the exp parameter in currencies.json, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in Telegram Stars. MaxTipAmount *int64 `json:"max_tip_amount,omitempty"` - // A JSON-serialized array of suggested amounts of tips in the smallest units of the currency (integer, not float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. + // A JSON-serialized Array of suggested amounts of tips in the smallest units of the currency (integer, not float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. SuggestedTipAmounts []int64 `json:"suggested_tip_amounts,omitempty"` // Unique deep-linking parameter. If left empty, forwarded copies of the sent message will have a Pay button, allowing multiple users to pay directly from the forwarded message, using the same invoice. If non-empty, forwarded copies of the sent message will have a URL button with a deep link to the bot (instead of a Pay button), with the value used as the start parameter. StartParameter string `json:"start_parameter,omitempty"` @@ -5011,7 +5264,7 @@ type CreateInvoiceLinkParams struct { SubscriptionPeriod *int64 `json:"subscription_period,omitempty"` // The maximum accepted amount for tips in the smallest units of the currency (integer, not float/double). For example, for a maximum tip of US$ 1.45 pass max_tip_amount = 145. See the exp parameter in currencies.json, it shows the number of digits past the decimal point for each currency (2 for the majority of currencies). Defaults to 0. Not supported for payments in Telegram Stars. MaxTipAmount *int64 `json:"max_tip_amount,omitempty"` - // A JSON-serialized array of suggested amounts of tips in the smallest units of the currency (integer, not float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. + // A JSON-serialized Array of suggested amounts of tips in the smallest units of the currency (integer, not float/double). At most 4 suggested tip amounts can be specified. The suggested tip amounts must be positive, passed in a strictly increased order and must not exceed max_tip_amount. SuggestedTipAmounts []int64 `json:"suggested_tip_amounts,omitempty"` // JSON-serialized data about the invoice, which will be shared with the payment provider. A detailed description of required fields should be provided by the payment provider. ProviderData string `json:"provider_data,omitempty"` @@ -5054,7 +5307,7 @@ type AnswerShippingQueryParams struct { ShippingQueryID string `json:"shipping_query_id"` // Pass True if delivery to the specified address is possible and False if there are any problems (for example, if delivery to the specified address is not possible) Ok bool `json:"ok"` - // Required if ok is True. A JSON-serialized array of available shipping options. + // Required if ok is True. A JSON-serialized Array of available shipping options. ShippingOptions []ShippingOption `json:"shipping_options,omitempty"` // Required if ok is False. Error message in human readable form that explains why it is impossible to complete the order (e.g. “Sorry, delivery to your desired address is unavailable”). Telegram will display this message to the user. ErrorMessage string `json:"error_message,omitempty"` @@ -5159,7 +5412,7 @@ func EditUserStarSubscription(ctx context.Context, b *client.Bot, p *EditUserSta type SetPassportDataErrorsParams struct { // User identifier UserID int64 `json:"user_id"` - // A JSON-serialized array describing the errors + // A JSON-serialized Array describing the errors Errors []PassportElementError `json:"errors"` } diff --git a/api/methods_gen_test.go b/api/methods_gen_test.go index af3c282..9aadbdf 100644 --- a/api/methods_gen_test.go +++ b/api/methods_gen_test.go @@ -19943,6 +19943,624 @@ func Test_StopPoll_ServerError(t *testing.T) { require.True(t, ae.IsRetryable(), "5xx must be retryable") } +func Test_EditEphemeralMessageText_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/editEphemeralMessageText") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_EditEphemeralMessageText_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_EditEphemeralMessageText_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_EditEphemeralMessageText_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_EditEphemeralMessageText_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_EditEphemeralMessageText_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_EditEphemeralMessageText_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := EditEphemeralMessageText(context.Background(), bot, &EditEphemeralMessageTextParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageText_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_EditEphemeralMessageText_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageText_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_EditEphemeralMessageText_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageTextParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Text: "test_value", + } + _, err := EditEphemeralMessageText(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + +func Test_EditEphemeralMessageMedia_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/editEphemeralMessageMedia") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_EditEphemeralMessageMedia_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_EditEphemeralMessageMedia_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_EditEphemeralMessageMedia_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_EditEphemeralMessageMedia_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_EditEphemeralMessageMedia_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_EditEphemeralMessageMedia_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := EditEphemeralMessageMedia(context.Background(), bot, &EditEphemeralMessageMediaParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageMedia_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_EditEphemeralMessageMedia_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageMedia_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_EditEphemeralMessageMedia_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageMediaParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + Media: nil, + } + _, err := EditEphemeralMessageMedia(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + +func Test_EditEphemeralMessageCaption_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/editEphemeralMessageCaption") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_EditEphemeralMessageCaption_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_EditEphemeralMessageCaption_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_EditEphemeralMessageCaption_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_EditEphemeralMessageCaption_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_EditEphemeralMessageCaption_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_EditEphemeralMessageCaption_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := EditEphemeralMessageCaption(context.Background(), bot, &EditEphemeralMessageCaptionParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageCaption_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_EditEphemeralMessageCaption_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageCaption_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_EditEphemeralMessageCaption_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageCaptionParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageCaption(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + +func Test_EditEphemeralMessageReplyMarkup_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/editEphemeralMessageReplyMarkup") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_EditEphemeralMessageReplyMarkup_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_EditEphemeralMessageReplyMarkup_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_EditEphemeralMessageReplyMarkup_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_EditEphemeralMessageReplyMarkup_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_EditEphemeralMessageReplyMarkup_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_EditEphemeralMessageReplyMarkup_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, &EditEphemeralMessageReplyMarkupParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageReplyMarkup_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_EditEphemeralMessageReplyMarkup_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_EditEphemeralMessageReplyMarkup_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_EditEphemeralMessageReplyMarkup_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &EditEphemeralMessageReplyMarkupParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := EditEphemeralMessageReplyMarkup(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + func Test_ApproveSuggestedPost_Success(t *testing.T) { m := &genTestMockDoer{} m.On("Do", mock.MatchedBy(func(r *http.Request) bool { @@ -20519,6 +21137,157 @@ func Test_DeleteMessages_ServerError(t *testing.T) { require.True(t, ae.IsRetryable(), "5xx must be retryable") } +func Test_DeleteEphemeralMessage_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/deleteEphemeralMessage") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_DeleteEphemeralMessage_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_DeleteEphemeralMessage_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_DeleteEphemeralMessage_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_DeleteEphemeralMessage_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_DeleteEphemeralMessage_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_DeleteEphemeralMessage_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := DeleteEphemeralMessage(context.Background(), bot, &DeleteEphemeralMessageParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_DeleteEphemeralMessage_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_DeleteEphemeralMessage_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_DeleteEphemeralMessage_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_DeleteEphemeralMessage_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &DeleteEphemeralMessageParams{ + ChatID: ChatIDFromInt(123), + ReceiverUserID: 42, + EphemeralMessageID: 42, + } + _, err := DeleteEphemeralMessage(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + func Test_DeleteMessageReaction_Success(t *testing.T) { m := &genTestMockDoer{} m.On("Do", mock.MatchedBy(func(r *http.Request) bool { diff --git a/api/types.gen.go b/api/types.gen.go index 40edb6f..e841000 100644 --- a/api/types.gen.go +++ b/api/types.gen.go @@ -70,6 +70,8 @@ type Update struct { RemovedChatBoost *ChatBoostRemoved `json:"removed_chat_boost,omitempty"` // Optional. A new bot was created to be managed by the bot, or token or owner of a managed bot was changed ManagedBot *ManagedBotUpdated `json:"managed_bot,omitempty"` + // Optional. User payment subscription has changed + Subscription *BotSubscriptionUpdated `json:"subscription,omitempty"` } // Describes the current status of a webhook. @@ -260,6 +262,8 @@ type ChatFullInfo struct { PaidMessageStarCount *int64 `json:"paid_message_star_count,omitempty"` // Optional. The bot that processes join request queries in the chat. The field is only available to chat administrators. GuardBot *User `json:"guard_bot,omitempty"` + // Optional. The Community to which the chat belongs + Community *Community `json:"community,omitempty"` } // UnmarshalJSON decodes ChatFullInfo by dispatching union-typed fields @@ -296,7 +300,7 @@ func (m *ChatFullInfo) UnmarshalJSON(data []byte) error { // This object represents a message. type Message struct { - // Unique message identifier inside this chat. In specific instances (e.g., message containing a video sent to a big chat), the server might automatically schedule a message instead of sending it immediately. In such cases, this field will be 0 and the relevant message will be unusable until it is actually sent. + // Unique message identifier inside this chat; 0 for ephemeral messages. In specific instances (e.g., a message containing a video sent to a big chat), the server might automatically schedule a message instead of sending it immediately. In such cases, this field will be 0 and the relevant message will be unusable until it is actually sent. MessageID int64 `json:"message_id"` // Optional. Unique identifier of a message thread or forum topic to which the message belongs; for supergroups and private chats only MessageThreadID *int64 `json:"message_thread_id,omitempty"` @@ -312,6 +316,10 @@ type Message struct { SenderBusinessBot *User `json:"sender_business_bot,omitempty"` // Optional. Tag or custom title of the sender of the message; for supergroups only SenderTag string `json:"sender_tag,omitempty"` + // Optional. For ephemeral messages, the user who received the message + ReceiverUser *User `json:"receiver_user,omitempty"` + // Optional. For ephemeral messages, identifier of the ephemeral message inside this chat. The identifier may be reused for another ephemeral message after the message is deleted or expires. + EphemeralMessageID *int64 `json:"ephemeral_message_id,omitempty"` // Date the message was sent in Unix time. It is always a positive number, representing a valid date. Date int64 `json:"date"` // Optional. The unique identifier for the guest query. Use this identifier with the method answerGuestQuery to send a response message. If non-empty, the message belongs to the chat where the guest bot was summoned, which may not coincide with other existing bot chats sharing the same identifier. @@ -326,7 +334,7 @@ type Message struct { IsTopicMessage *bool `json:"is_topic_message,omitempty"` // Optional. True, if the message is a channel post that was automatically forwarded to the connected discussion group IsAutomaticForward *bool `json:"is_automatic_forward,omitempty"` - // Optional. For replies in the same chat and message thread, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply. + // Optional. For replies in the same chat and message thread, the original message. Note that the Message object in this field will not contain further reply_to_message fields even if it itself is a reply. If the message is a reply to an ephemeral message, then this field may be omitted. ReplyToMessage *Message `json:"reply_to_message,omitempty"` // Optional. Information about the message that is being replied to, which may come from another chat or forum topic ExternalReply *ExternalReplyInfo `json:"external_reply,omitempty"` @@ -464,7 +472,7 @@ type Message struct { WriteAccessAllowed *WriteAccessAllowed `json:"write_access_allowed,omitempty"` // Optional. Telegram Passport data PassportData *PassportData `json:"passport_data,omitempty"` - // Optional. Service message. A user in the chat triggered another user's proximity alert while sharing Live Location. + // Optional. Service message: a user in the chat triggered another user's proximity alert while sharing Live Location ProximityAlertTriggered *ProximityAlertTriggered `json:"proximity_alert_triggered,omitempty"` // Optional. Service message: user boosted the chat BoostAdded *ChatBoostAdded `json:"boost_added,omitempty"` @@ -474,6 +482,10 @@ type Message struct { ChecklistTasksDone *ChecklistTasksDone `json:"checklist_tasks_done,omitempty"` // Optional. Service message: tasks were added to a checklist ChecklistTasksAdded *ChecklistTasksAdded `json:"checklist_tasks_added,omitempty"` + // Optional. Service message: chat added to a Community + CommunityChatAdded *CommunityChatAdded `json:"community_chat_added,omitempty"` + // Optional. Service message: chat removed from a Community + CommunityChatRemoved *CommunityChatRemoved `json:"community_chat_removed,omitempty"` // Optional. Service message: the price for paid messages in the corresponding direct messages chat of a channel has changed DirectMessagePriceChanged *DirectMessagePriceChanged `json:"direct_message_price_changed,omitempty"` // Optional. Service message: forum topic created @@ -733,13 +745,15 @@ func (m *ExternalReplyInfo) UnmarshalJSON(data []byte) error { // Describes reply parameters for the message that is being sent. type ReplyParameters struct { - // Identifier of the message that will be replied to in the current chat, or in the chat chat_id if it is specified - MessageID int64 `json:"message_id"` - // Optional. If the message to be replied to is from a different chat, unique identifier for the chat or username of the bot, supergroup or channel in the format @username. Not supported for messages sent on behalf of a business account and messages from channel direct messages chats. + // Optional. Identifier of the message that will be replied to in the current chat, or in the chat chat_id if it is specified. Required if ephemeral_message_id isn't specified. + MessageID *int64 `json:"message_id,omitempty"` + // Optional. If the message to be replied to is from a different chat, unique identifier for the chat or username of the bot, supergroup or channel in the format @username. Not supported for messages sent on behalf of a business account, messages from channel direct messages chats and ephemeral messages. ChatID *ChatID `json:"chat_id,omitempty"` - // Optional. Pass True if the message should be sent even if the specified message to be replied to is not found. Always False for replies in another chat or forum topic. Always True for messages sent on behalf of a business account. + // Optional. Identifier of the incoming ephemeral message that will be replied to in the current chat. A reply to an ephemeral message must itself be an ephemeral message. An ephemeral message may only be replied to within 15 seconds of being sent. Required if message_id isn't specified. + EphemeralMessageID *int64 `json:"ephemeral_message_id,omitempty"` + // Optional. Pass True if the message should be sent even if the specified message to be replied to is not found. Always False for replies in another chat or forum topic, and sent ephemeral messages. Always True for messages sent on behalf of a business account. AllowSendingWithoutReply *bool `json:"allow_sending_without_reply,omitempty"` - // Optional. Quoted part of the message to be replied to; 0-1024 characters after entities parsing. The quote must be an exact substring of the message to be replied to, including bold, italic, underline, strikethrough, spoiler, custom_emoji, and date_time entities. The message will fail to send if the quote isn't found in the original message. + // Optional. Quoted part of the message to be replied to; 0-1024 characters after entities parsing. The quote must be an exact substring of the message to be replied to, including bold, italic, underline, strikethrough, spoiler, custom_emoji, and date_time entities. The message will fail to send if the quote isn't found in the original message. Ignored for ephemeral messages. Quote string `json:"quote,omitempty"` // Optional. Mode for parsing entities in the quote. See formatting options for more details. QuoteParseMode ParseMode `json:"quote_parse_mode,omitempty"` @@ -1555,24 +1569,6 @@ type InputChecklist struct { OthersCanMarkTasksAsDone *bool `json:"others_can_mark_tasks_as_done,omitempty"` } -// Describes a service message about checklist tasks marked as done or not done. -type ChecklistTasksDone struct { - // Optional. Message containing the checklist whose tasks were marked as done or not done. Note that the Message object in this field will not contain the reply_to_message field even if it itself is a reply. - ChecklistMessage *Message `json:"checklist_message,omitempty"` - // Optional. Identifiers of the tasks that were marked as done - MarkedAsDoneTaskIds []int64 `json:"marked_as_done_task_ids,omitempty"` - // Optional. Identifiers of the tasks that were marked as not done - MarkedAsNotDoneTaskIds []int64 `json:"marked_as_not_done_task_ids,omitempty"` -} - -// Describes a service message about tasks added to a checklist. -type ChecklistTasksAdded struct { - // Optional. Message containing the checklist to which the tasks were added. Note that the Message object in this field will not contain the reply_to_message field even if it itself is a reply. - ChecklistMessage *Message `json:"checklist_message,omitempty"` - // List of tasks added to the checklist - Tasks []ChecklistTask `json:"tasks"` -} - // This object represents a point on the map. type Location struct { // Latitude as defined by the sender @@ -1645,6 +1641,16 @@ type ManagedBotUpdated struct { Bot User `json:"bot"` } +// This object contains information about changes to a user payment subscription toward the current bot. +type BotSubscriptionUpdated struct { + // User who subscribed for payments toward the bot + User User `json:"user"` + // Bot-specified invoice payload + InvoicePayload string `json:"invoice_payload"` + // The new state of the subscription. Currently, it can be one of “canceled” if the user canceled the subscription, “active” if the user re-enabled a previously canceled subscription, or “failed” if payment for the subscription failed. + State BotSubscriptionUpdatedState `json:"state"` +} + // Describes a service message about an option added to a poll. type PollOptionAdded struct { // Optional. Message containing the poll to which the option was added, if known. Note that the Message object in this field will not contain the reply_to_message field even if it itself is a reply. @@ -2083,6 +2089,34 @@ func (m *ChatBackground) UnmarshalJSON(data []byte) error { return nil } +// Describes a service message about checklist tasks marked as done or not done. +type ChecklistTasksDone struct { + // Optional. Message containing the checklist whose tasks were marked as done or not done. Note that the Message object in this field will not contain the reply_to_message field even if it itself is a reply. + ChecklistMessage *Message `json:"checklist_message,omitempty"` + // Optional. Identifiers of the tasks that were marked as done + MarkedAsDoneTaskIds []int64 `json:"marked_as_done_task_ids,omitempty"` + // Optional. Identifiers of the tasks that were marked as not done + MarkedAsNotDoneTaskIds []int64 `json:"marked_as_not_done_task_ids,omitempty"` +} + +// Describes a service message about tasks added to a checklist. +type ChecklistTasksAdded struct { + // Optional. Message containing the checklist to which the tasks were added. Note that the Message object in this field will not contain the reply_to_message field even if it itself is a reply. + ChecklistMessage *Message `json:"checklist_message,omitempty"` + // List of tasks added to the checklist + Tasks []ChecklistTask `json:"tasks"` +} + +// Describes a service message about a chat being added to a community. +type CommunityChatAdded struct { + // The new community to which the chat belongs + Community Community `json:"community"` +} + +// Describes a service message about a chat being removed from a community. Currently holds no information. +type CommunityChatRemoved struct { +} + // This object represents a service message about a new forum topic created in the chat. type ForumTopicCreated struct { // Name of the topic @@ -2195,7 +2229,7 @@ type PaidMessagePriceChanged struct { // Describes a service message about a change in the price of direct messages sent to a channel chat. type DirectMessagePriceChanged struct { - // True, if direct messages are enabled for the channel chat; false otherwise + // True, if direct messages are enabled for the channel chat; False otherwise AreDirectMessagesEnabled bool `json:"are_direct_messages_enabled"` // Optional. The new number of Telegram Stars that must be paid by users for each direct message sent to the channel. Does not apply to users who have been exempted by administrators. Defaults to 0. DirectMessageStarCount *int64 `json:"direct_message_star_count,omitempty"` @@ -2231,9 +2265,9 @@ type SuggestedPostDeclined struct { type SuggestedPostPaid struct { // Optional. Message containing the suggested post. Note that the Message object in this field will not contain the reply_to_message field even if it itself is a reply. SuggestedPostMessage *Message `json:"suggested_post_message,omitempty"` - // Currency in which the payment was made. Currently, one of “XTR” for Telegram Stars or “TON” for toncoins. + // Currency in which the payment was made. Currently, one of “XTR” for Telegram Stars or “TON” for TON grams. Currency SuggestedPostPaidCurrency `json:"currency"` - // Optional. The amount of the currency that was received by the channel in nanotoncoins; for payments in toncoins only + // Optional. The amount of the currency that was received by the channel in nanograms; for payments in TON grams only Amount *int64 `json:"amount,omitempty"` // Optional. The amount of Telegram Stars that was received by the channel; for payments in Telegram Stars only StarAmount *StarAmount `json:"star_amount,omitempty"` @@ -2331,9 +2365,9 @@ type LinkPreviewOptions struct { // Describes the price of a suggested post. type SuggestedPostPrice struct { - // Currency in which the post will be paid. Currently, must be one of “XTR” for Telegram Stars or “TON” for toncoins. + // Currency in which the post will be paid. Currently, must be one of “XTR” for Telegram Stars or “TON” for TON grams. Currency SuggestedPostPaidCurrency `json:"currency"` - // The amount of the currency that will be paid for the post in the smallest units of the currency, i.e. Telegram Stars or nanotoncoins. Currently, price in Telegram Stars must be between 5 and 100000, and price in nanotoncoins must be between 10000000 and 10000000000000. + // The amount of the currency that will be paid for the post in the smallest units of the currency, i.e. Telegram Stars or nanograms. Currently, price in Telegram Stars must be between 5 and 100000, and price in nanograms must be between 10000000 and 10000000000000. Amount int64 `json:"amount"` } @@ -2402,11 +2436,11 @@ type WebAppInfo struct { type ReplyKeyboardMarkup struct { // Array of button rows, each represented by an Array of KeyboardButton objects Keyboard [][]KeyboardButton `json:"keyboard"` - // Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to false, in which case the custom keyboard can be hidden and opened with a keyboard icon. + // Optional. Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to False, in which case the custom keyboard can be hidden and opened with a keyboard icon. IsPersistent *bool `json:"is_persistent,omitempty"` - // Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard. + // Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons). Defaults to False, in which case the custom keyboard is always of the same height as the app's standard keyboard. ResizeKeyboard *bool `json:"resize_keyboard,omitempty"` - // Optional. Requests clients to hide the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat - the user can press a special button in the input field to see the custom keyboard again. Defaults to false. + // Optional. Requests clients to hide the keyboard as soon as it's been used. The keyboard will still be available, but clients will automatically display the usual letter-keyboard in the chat - the user can press a special button in the input field to see the custom keyboard again. Defaults to False. OneTimeKeyboard *bool `json:"one_time_keyboard,omitempty"` // Optional. The placeholder to be shown in the input field when the keyboard is active; 1-64 characters InputFieldPlaceholder string `json:"input_field_placeholder,omitempty"` @@ -2631,6 +2665,14 @@ type ForceReply struct { Selective *bool `json:"selective,omitempty"` } +// Represents a community (a group of chats). +type Community struct { + // Unique identifier for this community. This number may have more than 32 significant bits and some programming languages may have difficulty/silent defects in interpreting it. But it has at most 52 significant bits, so a signed 64-bit integer or double-precision float type are safe for storing this identifier. + ID int64 `json:"id"` + // Name of the community + Name string `json:"name"` +} + // This object represents a chat photo. type ChatPhoto struct { // File identifier of small (160x160) chat photo. This file_id can be used only for photo download and only for as long as the photo is not changed. @@ -2703,7 +2745,7 @@ type ChatAdministratorRights struct { CanManageTopics *bool `json:"can_manage_topics,omitempty"` // Optional. True, if the administrator can manage direct messages of the channel and decline suggested posts; for channels only CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` - // Optional. True, if the administrator can edit the tags of regular members; for groups and supergroups only. If omitted defaults to the value of can_pin_messages. + // Optional. True, if the administrator can edit the tags of regular members; for groups and supergroups only. If omitted, defaults to the value of can_pin_messages. CanManageTags *bool `json:"can_manage_tags,omitempty"` } @@ -2891,7 +2933,7 @@ type ChatMemberAdministrator struct { CanManageTopics *bool `json:"can_manage_topics,omitempty"` // Optional. True, if the administrator can manage direct messages of the channel and decline suggested posts; for channels only CanManageDirectMessages *bool `json:"can_manage_direct_messages,omitempty"` - // Optional. True, if the administrator can edit the tags of regular members; for groups and supergroups only. If omitted defaults to the value of can_pin_messages. + // Optional. True, if the administrator can edit the tags of regular members; for groups and supergroups only. If omitted, defaults to the value of can_pin_messages. CanManageTags *bool `json:"can_manage_tags,omitempty"` // Optional. Custom title for this user CustomTitle string `json:"custom_title,omitempty"` @@ -3067,7 +3109,7 @@ type ChatJoinRequest struct { Bio string `json:"bio,omitempty"` // Optional. Chat invite link that was used by the user to send the join request InviteLink *ChatInviteLink `json:"invite_link,omitempty"` - // Optional. Identifier of the join request query. If present, then the bot must call sendChatJoinRequestWebApp or directly call answerChatJoinRequestQuery within 10 seconds. + // Optional. Identifier of the join request query; for bots assigned to process join requests only. If present, then the bot must call sendChatJoinRequestWebApp or directly call answerChatJoinRequestQuery within 10 seconds. QueryID string `json:"query_id,omitempty"` } @@ -3103,7 +3145,7 @@ type ChatPermissions struct { CanInviteUsers *bool `json:"can_invite_users,omitempty"` // Optional. True, if the user is allowed to pin messages. Ignored in public supergroups. CanPinMessages *bool `json:"can_pin_messages,omitempty"` - // Optional. True, if the user is allowed to create forum topics. If omitted defaults to the value of can_pin_messages. + // Optional. True, if the user is allowed to create forum topics. If omitted, defaults to the value of can_pin_messages. CanManageTopics *bool `json:"can_manage_topics,omitempty"` } @@ -3847,9 +3889,9 @@ type UniqueGiftInfo struct { Gift UniqueGift `json:"gift"` // Origin of the gift. Currently, either “upgrade” for gifts upgraded from regular gifts, “transfer” for gifts transferred from other users or channels, “resale” for gifts bought from other users, “gifted_upgrade” for upgrades purchased after the gift was sent, or “offer” for gifts bought or sold through gift purchase offers. Origin UniqueGiftInfoOrigin `json:"origin"` - // Optional. For gifts bought from other users, the currency in which the payment for the gift was done. Currently, one of “XTR” for Telegram Stars or “TON” for toncoins. + // Optional. For gifts bought from other users, the currency in which the payment for the gift was done. Currently, one of “XTR” for Telegram Stars or “TON” for TON grams. LastResaleCurrency SuggestedPostPaidCurrency `json:"last_resale_currency,omitempty"` - // Optional. For gifts bought from other users, the price paid for the gift in either Telegram Stars or nanotoncoins + // Optional. For gifts bought from other users, the price paid for the gift in either Telegram Stars or nanograms LastResaleAmount *int64 `json:"last_resale_amount,omitempty"` // Optional. Unique identifier of the received gift for the bot; only present for gifts received on behalf of business accounts OwnedGiftID string `json:"owned_gift_id,omitempty"` @@ -4063,6 +4105,8 @@ type BotCommand struct { Command string `json:"command"` // Description of the command; 1-256 characters Description string `json:"description"` + // Optional. True, if the command sends an ephemeral message, which can be seen only by the sender of the message and the bot + IsEphemeral *bool `json:"is_ephemeral,omitempty"` } // BotCommandScope is a union type. The following concrete variants implement @@ -4730,7 +4774,7 @@ func (*InputMediaVideo) isInputMedia() {} // Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent. type InputMediaAnimation struct { - // Type of the result, must be animation + // Type of the media, must be animation Type InputMediaType `json:"type"` // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data under name. More information on Sending Files » Media string `json:"media"` @@ -4742,7 +4786,7 @@ type InputMediaAnimation struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Optional. Pass True, if the caption must be shown above the message media + // Optional. Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Optional. Animation width Width *int64 `json:"width,omitempty"` @@ -4772,7 +4816,7 @@ func (v *InputMediaAnimation) MarshalJSON() ([]byte, error) { // Represents an audio file to be treated as music to be sent. type InputMediaAudio struct { - // Type of the result, must be audio + // Type of the media, must be audio Type InputMediaType `json:"type"` // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data under name. More information on Sending Files » Media string `json:"media"` @@ -4810,7 +4854,7 @@ func (v *InputMediaAudio) MarshalJSON() ([]byte, error) { // Represents a general file to be sent. type InputMediaDocument struct { - // Type of the result, must be document + // Type of the media, must be document Type InputMediaType `json:"type"` // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data under name. More information on Sending Files » Media string `json:"media"` @@ -4844,7 +4888,7 @@ func (v *InputMediaDocument) MarshalJSON() ([]byte, error) { // Represents an HTTP link to be sent. type InputMediaLink struct { - // Type of the result, must be link + // Type of the media, must be link Type InputPollOptionMediaType `json:"type"` // HTTP URL of the link URL string `json:"url"` @@ -4868,7 +4912,7 @@ func (v *InputMediaLink) MarshalJSON() ([]byte, error) { // Represents a live photo to be sent. type InputMediaLivePhoto struct { - // Type of the result, must be live_photo + // Type of the media, must be live_photo Type InputMediaType `json:"type"` // Video of the live photo to send. Pass a file_id to send a file that exists on the Telegram servers (recommended) or pass “attach://” to upload a new one using multipart/form-data under name. More information on Sending Files ». Sending live photos by a URL is currently unsupported. Media string `json:"media"` @@ -4880,7 +4924,7 @@ type InputMediaLivePhoto struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Optional. Pass True, if the caption must be shown above the message media + // Optional. Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Optional. Pass True if the live photo needs to be covered with a spoiler animation HasSpoiler *bool `json:"has_spoiler,omitempty"` @@ -4904,7 +4948,7 @@ func (v *InputMediaLivePhoto) MarshalJSON() ([]byte, error) { // Represents a location to be sent. type InputMediaLocation struct { - // Type of the result, must be location + // Type of the media, must be location Type InputPollOptionMediaType `json:"type"` // Latitude of the location Latitude float64 `json:"latitude"` @@ -4932,7 +4976,7 @@ func (v *InputMediaLocation) MarshalJSON() ([]byte, error) { // Represents a photo to be sent. type InputMediaPhoto struct { - // Type of the result, must be photo + // Type of the media, must be photo Type InputMediaType `json:"type"` // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data under name. More information on Sending Files » Media string `json:"media"` @@ -4942,7 +4986,7 @@ type InputMediaPhoto struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Optional. Pass True, if the caption must be shown above the message media + // Optional. Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Optional. Pass True if the photo needs to be covered with a spoiler animation HasSpoiler *bool `json:"has_spoiler,omitempty"` @@ -4966,7 +5010,7 @@ func (v *InputMediaPhoto) MarshalJSON() ([]byte, error) { // Represents a sticker file to be sent. type InputMediaSticker struct { - // Type of the result, must be sticker + // Type of the media, must be sticker Type InputPollOptionMediaType `json:"type"` // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a .WEBP sticker from the Internet, or pass “attach://” to upload a new .WEBP, .TGS, or .WEBM sticker using multipart/form-data under name. More information on Sending Files » Media string `json:"media"` @@ -4992,7 +5036,7 @@ func (v *InputMediaSticker) MarshalJSON() ([]byte, error) { // Represents a venue to be sent. type InputMediaVenue struct { - // Type of the result, must be venue + // Type of the media, must be venue Type InputPollOptionMediaType `json:"type"` // Latitude of the location Latitude float64 `json:"latitude"` @@ -5030,7 +5074,7 @@ func (v *InputMediaVenue) MarshalJSON() ([]byte, error) { // Represents a video to be sent. type InputMediaVideo struct { - // Type of the result, must be video + // Type of the media, must be video Type InputMediaType `json:"type"` // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass “attach://” to upload a new one using multipart/form-data under name. More information on Sending Files » Media string `json:"media"` @@ -5046,7 +5090,7 @@ type InputMediaVideo struct { ParseMode ParseMode `json:"parse_mode,omitempty"` // Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` - // Optional. Pass True, if the caption must be shown above the message media + // Optional. Pass True if the caption must be shown above the message media ShowCaptionAboveMedia *bool `json:"show_caption_above_media,omitempty"` // Optional. Video width Width *int64 `json:"width,omitempty"` @@ -5076,6 +5120,22 @@ func (v *InputMediaVideo) MarshalJSON() ([]byte, error) { }) } +// Represents a voice message file to be sent. +type InputMediaVoiceNote struct { + // Type of the media, must be voice_note + Type InputMediaVoiceNoteType `json:"type"` + // File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet, or pass "attach://" to upload a new one using multipart/form-data under name. More information on Sending Files » + Media string `json:"media"` + // Optional. Caption of the voice message to be sent, 0-1024 characters after entities parsing + Caption string `json:"caption,omitempty"` + // Optional. Mode for parsing entities in the voice message caption. See formatting options for more details. + ParseMode ParseMode `json:"parse_mode,omitempty"` + // Optional. List of special entities that appear in the caption, which can be specified instead of parse_mode + CaptionEntities []MessageEntity `json:"caption_entities,omitempty"` + // Optional. Duration of the voice message in seconds + Duration *int64 `json:"duration,omitempty"` +} + // InputPaidMedia is a union type. The following concrete variants implement // it: // - InputPaidMediaLivePhoto @@ -5396,18 +5456,30 @@ type RichMessage struct { IsRtl *bool `json:"is_rtl,omitempty"` } -// Describes a rich message to be sent. Exactly one of the fields html or markdown must be used. +// Describes a rich message to be sent. Exactly one of the fields html, markdown, or blocks must be used. type InputRichMessage struct { - // Optional. Content of the rich message to send described using HTML formatting. See rich message formatting options for more details. + // Optional. Content of the rich message to send described as a list of blocks + Blocks []InputRichBlock `json:"blocks,omitempty"` + // Optional. Content of the rich message to send described using HTML formatting. See rich message formatting options for more details. Use media field to specify the media used in the message. HTML string `json:"html,omitempty"` - // Optional. Content of the rich message to send described using Markdown formatting. See rich message formatting options for more details. + // Optional. Content of the rich message to send described using Markdown formatting. See rich message formatting options for more details. Use media field to specify the media used in the message. Markdown string `json:"markdown,omitempty"` + // Optional. List of media that are specified in the markdown or html fields using tg://photo?id=, tg://video?id=, and tg://audio?id= links + Media []InputRichMessageMedia `json:"media,omitempty"` // Optional. Pass True if the rich message must be shown right-to-left IsRtl *bool `json:"is_rtl,omitempty"` // Optional. Pass True to skip automatic detection of entities (e.g., URLs, email addresses, username mentions, hashtags, cashtags, bot commands, or phone numbers) in the text SkipEntityDetection *bool `json:"skip_entity_detection,omitempty"` } +// Describes a media element embedded in an outgoing rich message. +type InputRichMessageMedia struct { + // Unique identifier of the media used in a tg://photo?id=, tg://video?id=, or tg://audio?id= link. 1-64 characters, only A-Z, a-z, 0-9, _ and - are allowed. + ID string `json:"id"` + // The media to be sent. Everything except the media itself and its properties is ignored. + Media any `json:"media"` +} + // RichText is a union type. The following concrete variants implement // it: // - RichTextBold @@ -6716,7 +6788,7 @@ func (v *RichBlockAudio) MarshalJSON() ([]byte, error) { }) } -// A block with a photo, corresponding to the HTML tag . +// A block with a photo, corresponding to the HTML tag . type RichBlockPhoto struct { // Type of the block, always “photo” Type RichBlockType `json:"type"` @@ -6798,11 +6870,11 @@ func (v *RichBlockVoiceNote) MarshalJSON() ([]byte, error) { }) } -// A block with a “Thinking…” placeholder, corresponding to the custom HTML tag . The block may be used only in sendRichMessageDraft, therefore it can't be received in messages. See https://t.me/addemoji/AIActions for examples of custom emoji, which are recommended for usage in the block. +// A block with a “Thinking…” placeholder, corresponding to the custom HTML tag . The block may be used only in sendRichMessageDraft, therefore it can't be received in messages. See https://t.me/addemoji/AIActions for examples of custom emoji that are recommended for usage in the block. type RichBlockThinking struct { // Type of the block, always “thinking” Type RichBlockType `json:"type"` - // Text of the block. See https://t.me/addemoji/AIActions for examples of custom emoji, which are recommended for usage in the block. + // Text of the block. See https://t.me/addemoji/AIActions for examples of custom emoji that are recommended for usage in the block. Text RichText `json:"text"` } @@ -6822,6 +6894,652 @@ func (v *RichBlockThinking) MarshalJSON() ([]byte, error) { }) } +// An item of a list to be sent. +type InputRichBlockListItem struct { + // The content of the item + Blocks []InputRichBlock `json:"blocks"` + // Optional. Pass True if the item has a checkbox + HasCheckbox *bool `json:"has_checkbox,omitempty"` + // Optional. Pass True if the item has a checked checkbox + IsChecked *bool `json:"is_checked,omitempty"` + // Optional. For ordered lists, the numeric value of the item label + Value *int64 `json:"value,omitempty"` + // Optional. For ordered lists, the type of the item label; must be one of “a” for lowercase letters, “A” for uppercase letters, “i” for lowercase Roman numerals, “I” for uppercase Roman numerals, or “1” for decimal numbers + Type RichBlockListItemType `json:"type,omitempty"` +} + +// InputRichBlock is a union type. The following concrete variants implement +// it: +// - InputRichBlockParagraph +// - InputRichBlockSectionHeading +// - InputRichBlockPreformatted +// - InputRichBlockFooter +// - InputRichBlockDivider +// - InputRichBlockMathematicalExpression +// - InputRichBlockAnchor +// - InputRichBlockList +// - InputRichBlockBlockQuotation +// - InputRichBlockPullQuotation +// - InputRichBlockCollage +// - InputRichBlockSlideshow +// - InputRichBlockTable +// - InputRichBlockDetails +// - InputRichBlockMap +// - InputRichBlockAnimation +// - InputRichBlockAudio +// - InputRichBlockPhoto +// - InputRichBlockVideo +// - InputRichBlockVoiceNote +// - InputRichBlockThinking +// +// This object represents a block in a rich formatted message to be sent. Currently, it can be any of the following types: +type InputRichBlock interface{ isInputRichBlock() } + +// isInputRichBlock is the marker method that makes InputRichBlockParagraph implement InputRichBlock. +func (*InputRichBlockParagraph) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockSectionHeading implement InputRichBlock. +func (*InputRichBlockSectionHeading) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockPreformatted implement InputRichBlock. +func (*InputRichBlockPreformatted) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockFooter implement InputRichBlock. +func (*InputRichBlockFooter) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockDivider implement InputRichBlock. +func (*InputRichBlockDivider) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockMathematicalExpression implement InputRichBlock. +func (*InputRichBlockMathematicalExpression) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockAnchor implement InputRichBlock. +func (*InputRichBlockAnchor) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockList implement InputRichBlock. +func (*InputRichBlockList) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockBlockQuotation implement InputRichBlock. +func (*InputRichBlockBlockQuotation) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockPullQuotation implement InputRichBlock. +func (*InputRichBlockPullQuotation) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockCollage implement InputRichBlock. +func (*InputRichBlockCollage) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockSlideshow implement InputRichBlock. +func (*InputRichBlockSlideshow) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockTable implement InputRichBlock. +func (*InputRichBlockTable) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockDetails implement InputRichBlock. +func (*InputRichBlockDetails) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockMap implement InputRichBlock. +func (*InputRichBlockMap) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockAnimation implement InputRichBlock. +func (*InputRichBlockAnimation) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockAudio implement InputRichBlock. +func (*InputRichBlockAudio) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockPhoto implement InputRichBlock. +func (*InputRichBlockPhoto) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockVideo implement InputRichBlock. +func (*InputRichBlockVideo) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockVoiceNote implement InputRichBlock. +func (*InputRichBlockVoiceNote) isInputRichBlock() {} + +// isInputRichBlock is the marker method that makes InputRichBlockThinking implement InputRichBlock. +func (*InputRichBlockThinking) isInputRichBlock() {} + +// A text paragraph, corresponding to the HTML tag

. +type InputRichBlockParagraph struct { + // Type of the block, always “paragraph” + Type InputRichBlockType `json:"type"` + // Text of the block + Text RichText `json:"text"` +} + +// MarshalJSON encodes InputRichBlockParagraph with the discriminator field +// "type" forced to "paragraph". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *InputRichBlockParagraph) MarshalJSON() ([]byte, error) { + type alias InputRichBlockParagraph + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "paragraph", + alias: (*alias)(v), + }) +} + +// A section heading, corresponding to the HTML tags

,

,

,

,

, or
. +type InputRichBlockSectionHeading struct { + // Type of the block, always “heading” + Type InputRichBlockType `json:"type"` + // Text of the block + Text RichText `json:"text"` + // Relative size of the text font; 1-6, 1 is the largest, 6 is the smallest + Size int64 `json:"size"` +} + +// MarshalJSON encodes InputRichBlockSectionHeading with the discriminator field +// "type" forced to "heading". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *InputRichBlockSectionHeading) MarshalJSON() ([]byte, error) { + type alias InputRichBlockSectionHeading + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "heading", + alias: (*alias)(v), + }) +} + +// A preformatted text block, corresponding to the nested HTML tags
 and .
+type InputRichBlockPreformatted struct {
+	// Type of the block, always “pre”
+	Type InputRichBlockType `json:"type"`
+	// Text of the block
+	Text RichText `json:"text"`
+	// Optional. The programming language of the text
+	Language string `json:"language,omitempty"`
+}
+
+// MarshalJSON encodes InputRichBlockPreformatted with the discriminator field
+// "type" forced to "pre".
+// The hardcoded value frees callers from setting Type by hand —
+// any user-supplied value on the struct literal is overridden so a typo
+// can't slip through to Telegram.
+func (v *InputRichBlockPreformatted) MarshalJSON() ([]byte, error) {
+	type alias InputRichBlockPreformatted
+	return json.Marshal(&struct {
+		Type string `json:"type"`
+		*alias
+	}{
+		Type:  "pre",
+		alias: (*alias)(v),
+	})
+}
+
+// A footer, corresponding to the HTML tag