diff --git a/4/payments.html b/4/payments.html index 8effb9d..ec7bd04 100644 --- a/4/payments.html +++ b/4/payments.html @@ -263,8 +263,8 @@
For physical goods, before starting, you need to talk to @BotFather, select one of the supported +
Before starting, you need to talk to @BotFather, select one of the supported Payment providers (you need to open an account on the provider website), and complete the connection procedure linking your bot with your provider account.
@@ -356,6 +356,9 @@For physical goods, before starting, you need to talk to @BotFather, select one of the supported +
Before starting, you need to talk to @BotFather, select one of the supported Payment providers (you need to open an account on the provider website), and complete the connection procedure linking your bot with your provider account.
@@ -4548,6 +4548,9 @@sendMessage
method\", parseMode: ParseMode.Html, protectContent: true, replyParameters: update.Message.MessageId, replyMarkup: new InlineKeyboardMarkup( InlineKeyboardButton.WithUrl(\"Check sendMessage method\", \"https://core.telegram.org/bots/api#sendmessage\"))); The method SendTextMessageAsync of .NET Bot Client maps to sendMessage on Telegram's Bot API. This method sends a text message and returns the message object sent. text is written in HTML format and parseMode indicates that. You can also write in Markdown or plain text. By passing protectContent we prevent the message (and eventual media) to be copiable/forwardable elsewhere. It's a good idea to make it clear to a user the reason why the bot is sending this message and that's why we pass the user's message id for replyParameters. You have the option of specifying a replyMarkup when sending messages. Reply markups are explained in details later in this book. Here we used an Inline Keyboard Markup with a button that attaches to the message itself. Clicking that opens sendMessage method documentation in the browser.","breadcrumbs":"Beginner » Sending Messages » Text » Send Text Message","id":"15","title":"Send Text Message"},"150":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots only get messages at the moment they are posted. You could archive them all in a database for later retrieval.","breadcrumbs":"Frequently Asked Questions » 8. How to fetch previous messages?","id":"150","title":"8. How to fetch previous messages?"},"151":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots can only get the list of admins (GetChatAdministratorsAsync) or detail about one specific member (GetChatMemberAsync) Alternatively, you can keep track of users by observing new messages in a chat and saving user info into a database.","breadcrumbs":"Frequently Asked Questions » 9. How to fetch a list of all users in chat?","id":"151","title":"9. How to fetch a list of all users in chat?"},"152":{"body":"You can't. Bots can only send private messages to users that have already initiated a private chat with your bot.","breadcrumbs":"Frequently Asked Questions » 10. How to send a private message to some random user?","id":"152","title":"10. How to send a private message to some random user?"},"153":{"body":"You would have received an update.MyChatMember with NewChatMember.Status == ChatMemberStatus.Kicked If you didn't record that info, you can try to SendChatActionAsync and see if it raises an exception.","breadcrumbs":"Frequently Asked Questions » 11. How to detect if a user blocked my bot?","id":"153","title":"11. How to detect if a user blocked my bot?"},"154":{"body":"Set the media.Caption (and media.ParseMode) on the first media","breadcrumbs":"Frequently Asked Questions » 12. How to set a caption to a media group (album)?","id":"154","title":"12. How to set a caption to a media group (album)?"},"155":{"body":"Either you can code a complex state machine workflow, saving where each user is currently in the discussion. Or you can just use YourEasyBot which makes sequential bots very simple to write... (or one of the other frameworks available for Telegram.Bot)","breadcrumbs":"Frequently Asked Questions » 13. How to write a bot that make questions/answers with users?","id":"155","title":"13. How to write a bot that make questions/answers with users?"},"156":{"body":"Pass a ParseMode.Html (or ParseMode.MarkDownV2) to argument parseMode. See formatting options . ⚠️ I highly recommend you choose HTML formatting because MarkDownV2 has A LOT of annoyingly reserved characters and you will regret it later.","breadcrumbs":"Frequently Asked Questions » 14. How to make font effects in message?","id":"156","title":"14. How to make font effects in message?"},"157":{"body":"I would recommend you make an ASP.NET webhook bot and host it on some WebApp hosting service. For example, Azure WebApp Service has a F1 Free plan including 1 GB disk, 1 GB ram, 60 minutes of daily cumulated active CPU usage (more than enough for most bots without heavy use) . And publishing to Azure is very easy from VS. A credit-card is necessary but you shouldn't get charged if you stay within quotas. Other cloud providers might also offer similar services.","breadcrumbs":"Frequently Asked Questions » 15. Where can I host my bot online for cheap/free?","id":"157","title":"15. Where can I host my bot online for cheap/free?"},"158":{"body":"See https://limits.tginfo.me for a list of limitations.","breadcrumbs":"Frequently Asked Questions » 16. Is there some limitation/maximum about feature X?","id":"158","title":"16. Is there some limitation/maximum about feature X?"},"159":{"body":"You can either do this via @BotFather (static entries) , or you can use SetMyCommandsAsync for more advanced settings ⚠️ This can only be filled with bot commands, starting with a / and containing only latin characters a-z_0-9","breadcrumbs":"Frequently Asked Questions » 17. How to populate the bot Menu button / commands list?","id":"159","title":"17. How to populate the bot Menu button / commands list?"},"16":{"body":"Almost all of the methods for sending messages return you the message you just sent. Let's have a look at this object. Add this statement after the previous code. Console.WriteLine( $\"{message.From.FirstName} sent message {message.MessageId} \" + $\"to chat {message.Chat.Id} at {message.Date}. \" + $\"It is a reply to message {message.ReplyToMessage.MessageId} \" + $\"and has {message.Entities.Length} message entities.\"); Output should look similar to this: Awesome bot sent message 123 to chat 123456789 at 8/21/18 11:25:09 AM. It is a reply to message 122 and has 2 message entities. There are a few things to note. Date and time is in UTC format and not your local timezone. Convert it to local time by calling message.Date.ToLocalTime() method. Message Entity refers to those formatted parts of the text: all the parameters in bold and sendMessage in mono-width font. Property message.Entities holds the formatting information and message.EntityValues gives you the actual value. For example, in the message we just sent: message.Entities.First().Type == MessageEntityType.Bold\nmessage.EntityValues.First() == \"all the parameters\" Try putting a breakpoint in the code to examine all the properties on a message objects you get.","breadcrumbs":"Beginner » Sending Messages » Text » The Sent Message","id":"16","title":"The Sent Message"},"160":{"body":"You should specify all update types including ChatMember in AllowedUpdates array on StartReceiving:ReceiverOptions or SetWebhookAsync","breadcrumbs":"Frequently Asked Questions » 18. How to receive ChatMember updates?","id":"160","title":"18. How to receive ChatMember updates?"},"161":{"body":"Pass true into StartReceiving:ReceiverOptions:DropPendingUpdates or SetWebhookAsync:dropPendingUpdates Alternatively, you can call await bot.DropPendingUpdatesAsync() before polling or using bot.OnUpdate .","breadcrumbs":"Frequently Asked Questions » 19. How to get rid of past updates when I restart my bot?","id":"161","title":"19. How to get rid of past updates when I restart my bot?"},"162":{"body":"Make sure you await until the end of the send method before closing the file (a \"using\" clause would close the file on leaving the current { scope } If you just filled a MemoryStream, make sure to rewind it to the beginning with ms.Position = 0; before sending If you send a media group, make sure you specify different filenames on InputFile.FromStream","breadcrumbs":"Frequently Asked Questions » 20. Difficulties to upload & send a file/media?","id":"162","title":"20. Difficulties to upload & send a file/media?"},"163":{"body":"Medias in a media group are received as separate consecutive messages having the same MediaGroupId property. You should collect them progressively as you receive those messages. There is no way to know how many medias are in the album, so: look for consecutive messages in that chat with same MediaGroupId and stop when it's not the same stop after 10 media in the group (maximum) use a timeout of a few seconds not receiving new messages in that chat to determine the end","breadcrumbs":"Frequently Asked Questions » 21. How to fetch all medias from an album/media group ?","id":"163","title":"21. How to fetch all medias from an album/media group ?"},"164":{"body":"⚠️ It costs about ~$5,000 !! 😱 First you need to buy a reserved username on Fragment . Then you need to pay an additional upgrade fee of 1K TON to apply that username to your bot. Finally, your bot can now post custom emojis using specific HTML or Markdown syntax (or entity). To post to a specific group, there is an alternative solution: Have premium members boost your group to Level 4. Then you can assign a custom emoji pack to your group that your members AND bots can use freely in group messages.","breadcrumbs":"Frequently Asked Questions » 22. How to send a custom emoji❓","id":"164","title":"22. How to send a custom emoji❓"},"165":{"body":"A new lead developer (Wizou) is now in charge of the library and commits to reduce code-breaking changes in the future. Version 21.x of the library have been much improved to facilitate migration from previous versions of the library, and include a lot of helpers/implicit operators to simplify your code.","breadcrumbs":"Frequently Asked Questions » 23. How to upgrade my existing code? You keep breaking compatibility!","id":"165","title":"23. How to upgrade my existing code? You keep breaking compatibility!"},"166":{"body":"You can call API methods (like sending messages) from several instances in parallel BUT only one instance can call method GetUpdates (or else you will receive Telegram API Error 409: Conflict: terminated by other getUpdates request )","breadcrumbs":"Frequently Asked Questions » 24. Can I use several apps/instance to manage my bot?","id":"166","title":"24. Can I use several apps/instance to manage my bot?"},"167":{"body":"You can't with Bot API but it's possible with WTelegramBot . Alternatively, you could store in database the mapping of UserId<->Username. Remember that not every user has a username.","breadcrumbs":"Frequently Asked Questions » 25. How do I get the user id from a username?","id":"167","title":"25. How do I get the user id from a username?"},"168":{"body":"Your bot has to be added as administrator of the channel. You will then receive the messages as update.ChannelPost or update.EditedChannelPost.","breadcrumbs":"Frequently Asked Questions » 26. How to receive messages from channels?","id":"168","title":"26. How to receive messages from channels?"},"169":{"body":"The first time, you will send the media with a stream (upload). Next times, you will use its FileId : var sent = await bot.SendVideoAsync(chatId, stream, ....);\nvar fileId = sent.Video.FileId // next times:\nawait bot.SendVideoAsync(chatId2, fileId, ...); For photos, use sent.Photo[^1].FileId","breadcrumbs":"Frequently Asked Questions » 27. How to sent the same media multiple times","id":"169","title":"27. How to sent the same media multiple times"},"17":{"body":"You can provide the source file for almost all multimedia messages (e.g. photo, video) in 3 ways: Uploading a file with the HTTP request HTTP URL for Telegram to get a file from the internet file_id of an existing file on Telegram servers ( recommended ) Examples in this section show all three. You will learn more about them later on when we discuss file upload and download .","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo and Sticker Messages","id":"17","title":"Photo and Sticker Messages"},"170":{"body":"Feel free to join our Telegram group and ask your question there","breadcrumbs":"Frequently Asked Questions » This FAQ doesn't have my question on it","id":"170","title":"This FAQ doesn't have my question on it"},"171":{"body":"Migrate to v21.* Migrate to v19.* Migrate to v18.* Migrate to v17.* Migrate to v14.*","breadcrumbs":"Migration guides to newer versions » Migration guides to newer versions of the library","id":"171","title":"Migration guides to newer versions of the library"},"172":{"body":"Important notes: Don't bother about version 20, migrate directly to version 21.* You won't find this version on Nuget: See this guide to install it in your programs . Version 21.8 supports Bot API 7.8 (including Telegram Stars payments ) Library is now based on System.Text.Json and doesn't depend on NewtonsoftJson anymore. ( See below )","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Migration guide for version 21.x","id":"172","title":"Migration guide for version 21.x"},"173":{"body":"That parameter was renamed and you can still pass a messageId for simple replies. Or you can pass a ReplyParameters structure for more advanced reply configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter replyToMessageId: → replyParameters:","id":"173","title":"Renamed parameter replyToMessageId: → replyParameters:"},"174":{"body":"That parameter was renamed and you can still pass true to disable web preview. Or you can pass a LinkPreviewOptions structure for more precise preview configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter disableWebPagePreview: → linkPreviewOptions:","id":"174","title":"Renamed parameter disableWebPagePreview: → linkPreviewOptions:"},"175":{"body":"Many boolean parameters or fields are now simply of type bool. In most cases, it shouldn't impact your existing code, or rather simplify it. Previously null values are now just false.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed bool? → bool","id":"175","title":"Changed bool? → bool"},"176":{"body":"When you don't need to specify a ParseMode, just pass default or ParseMode.None.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed ParseMode? → ParseMode","id":"176","title":"Changed ParseMode? → ParseMode"},"177":{"body":"We added/restored features & implicit conversions that make your code simpler: InputFile: just pass a string/Stream for file_id/url/stream content (as was possible in previous versions of Telegram.Bot) InputMedia*: just pass an InputFile when you don't need to associate caption or such MessageId: auto-converts to/from int (and also from Message) ReactionType: just pass a string when you want to send an emoji ReactionType: just pass a long when you want to send a custom emoji (id) Some other obvious implicit conversion operators for structures containing a single property No more enforcing init; properties, so you can adjust the content of fields as you wish or modify a structure returned by the API (before passing it back to the API if you want) No more JSON \"required properties\" during deserialization, so your old saved JSON files won't break if a field is added/renamed. Restored some MessageType enum values that were removed (renamed) recently (easier compatibility)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Better backward-compatibility and simplification of code","id":"177","title":"Better backward-compatibility and simplification of code"},"178":{"body":"This class hierarchy was introduced in Bot API 7.0 and broke existing code and added unnecessary complexity. This was removed in our library v21 and you will just receive directly a Message (as before) . To identify an \"inaccessible message\", you can just check message.Type == MessageType.Unknown or message.Date == default.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » MaybeInaccessibleMessage","id":"178","title":"MaybeInaccessibleMessage"},"179":{"body":"In previous versions, the big Chat structure contained many fields that were filled only after a call to GetChatAsync. This structure is now split into Chat and ChatFullInfo structures. The new Chat structure contains only common fields that are always filled. The new ChatFullInfo structure inherits from Chat and is returned only by GetChatAsync method, with all the extra fields.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Chat and ChatFullInfo","id":"179","title":"Chat and ChatFullInfo"},"18":{"body":"send photo method photo tests Sending a photo is simple. Here is an example: var message = await bot.SendPhotoAsync(chatId, \"https://telegrambots.github.io/book/docs/photo-ara.jpg\", caption: \"Ara bird. Source: Pixabay\", parseMode: ParseMode.Html); photo message","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo","id":"18","title":"Photo"},"180":{"body":"Request structures (types ending with Request) are NOT the recommended way to use the library in your projects. They are to be considered as low-level raw access to Bot API structures for advanced programmers, and might change/break at any time in the future. If you have existing code using them, you can use the MakeRequestAsync method to send those requests. (Other methods based on those requests will be removed soon)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Request structures","id":"180","title":"Request structures"},"181":{"body":"To make a payment in Telegram Stars with SendInvoiceAsync, set the following parameters: providerToken: null or \"\" currency: \"XTR\" prices: with a single price no tip amounts","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Payments with Telegram Stars","id":"181","title":"Payments with Telegram Stars"},"182":{"body":"The library now uses System.Text.Json instead of NewtonsoftJson. To make it work in your ASP.NET projects, you should now: Remove package Microsoft.AspNetCore.Mvc.NewtonsoftJson from your project dependencies Follow our Webhook page to configure your web app correctly","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Webhooks with System.Text.Json","id":"182","title":"Webhooks with System.Text.Json"},"183":{"body":"SendPollAsync now expect an array of InputPollOption instead of string. But we added an implicit conversion from string to InputPollOption, so the change is minimal: // before:\nawait bot.SendPollAsync(chatId, \"question\", new[] { \"answer1\", \"answer2\" });\n// after:\nawait bot.SendPollAsync(chatId, \"question\", new InputPollOption[] { \"answer1\", \"answer2\" });","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » InputPollOption in SendPollAsync","id":"183","title":"InputPollOption in SendPollAsync"},"184":{"body":"You can now specify a global CancellationToken directly in TelegramBotClient constructor. This way, you won't need to pass a cancellationToken to every method call after that (if you just need one single cancellation token for stopping your bot)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Global cancellation token (v21.2)","id":"184","title":"Global cancellation token (v21.2)"},"185":{"body":"warning That's a change of behaviour, but most of you will probably welcome this change If you forgot to wrap your HandleUpdateAsync code in a big try..catch, and your code happen to throw an exception, this would previously stop the polling completely. Now the Polling system will catch your exceptions, pass them to your HandleErrorAsync method and continue the polling . In previous versions of the library: ReceiveAsync would throw out the exception (therefore stopping the polling) StartReceiving would pass the exception to HandlePollingErrorAsync and silently stop the polling If you still want the previous behaviour, have your HandleErrorAsync start like this: Task HandleErrorAsync(ITelegramBotClient bot, Exception ex, HandleErrorSource source, CancellationToken ct)\n{ if (source is HandleErrorSource.HandleUpdateError) throw ex; ...","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Polling system now catch exceptions in your HandleUpdate code (v21.3)","id":"185","title":"Polling system now catch exceptions in your HandleUpdate code (v21.3)"},"186":{"body":"When replying to a message, you can now simply pass a Message for replyParameters: rather than a Message.MessageId Update.AllTypes is a constant array containing all UpdateTypes. You can pass it for the allowedUpdates: parameter (GetUpdatesAsync/SetWebhookAsync) Message has now 2 extensions methods: .ToHtml() and .ToMarkdown() to convert the message text/caption and their entities into a simple Html or Markdown string. You can also use methods Markdown.Escape() and HtmlText.Escape() to sanitize reserved characters from strings Reply/Inline Keyboard Markup now have construction methods to simplify building keyboards dynamically: var replyMarkup = new InlineKeyboardMarkup() .AddButton(InlineKeyboardButton.WithUrl(\"Link to Repository\", \"https://github.com/TelegramBots/Telegram.Bot\")) .AddNewRow().AddButton(\"callback\").AddButton(\"caption\", \"data\") .AddNewRow(\"with\", \"three\", \"buttons\") .AddNewRow().AddButtons(\"A\", \"B\", InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(\"switch\")); Same for ReplyKeyboardMarkup (and you can use new ReplyKeyboardMarkup(true) to resize keyboard) As previously announced , the Request-typed methods are gone. But you can still send Request structures via the MakeRequestAsync method.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » New helpers/extensions to simplify your code (v21.5)","id":"186","title":"New helpers/extensions to simplify your code (v21.5)"},"187":{"body":"Instead of StartReceiving/ReceiveAsync system, you can now simply set 2 or 3 events on the botClient: bot.OnMessage += ... to receive Message updates bot.OnUpdate += ... to receive other updates (or all updates if you don't set OnMessage) bot.OnError += ... to handle errors/exceptions during polling or your handlers Note: Second argument to OnMessage event specifies which kind of update it was ( edited , channel or business message?) When you assign those events, polling starts automatically, you don't have anything to do. Polling will stop when you remove (-=) your events, or when you cancel the global cancellation token You can also use await bot.DropPendingUpdatesAsync() before setting those events to ignore past updates. The Console example project has been updated to demonstrate these events.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Simplified polling with events (v21.7)","id":"187","title":"Simplified polling with events (v21.7)"},"188":{"body":"If Telegram servers fail on your API call with this error and ask you to to retry in less than 60 seconds, TelegramBotClient will now automatically wait for the requested delay and retry sending the same request up to 3 times. This is configurable using Options on the constructor: using var cts = new CancellationTokenSource();\nvar options = new TelegramBotClientOptions(token) { RetryThreshold = 120, RetryCount = 2 };\nvar bot = new TelegramBotClient(options, cancellationToken: cts.Token); *️⃣ This is a change of behavior compared to previous versions, but probably a welcome one. To disable this system and keep the same behavior as previous versions, use RetryThreshold = 0 Notes for advanced users: If this happens while uploading files (InputFile streams), the streams will be reset to their start position in order to be sent again If your streams are non-seekable (no problem with MemoryStream/FileStream) , the full HTTP request to Bot API will be buffered before the first sending (so it can lead to a temporary use of memory if you're sending big files)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)","id":"188","title":"Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)"},"189":{"body":"","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Migration guide for version 19.0","id":"189","title":"Migration guide for version 19.0"},"19":{"body":"Multimedia messages can optionally have a caption attached to them. Here we sent a caption in HTML format. A user can click on Pixabay in the caption to open its URL in the browser. Similar to message entities discussed before, caption entities on Message object are the result of parsing formatted(Markdown or HTML) caption text. Try inspecting these properties in debug mode: message.Caption: caption in plain text without formatting message.CaptionEntities: info about special entities in the caption message.CaptionEntityValues: text values of mentioned entities","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Caption","id":"19","title":"Caption"},"190":{"body":"New topics functionality allow bots interact with users in topic specified by messageThreadId parameter. We try to keep our Bot API implementation as close to Telegram Bot API as possible. This means, that the new messageThreadId now the first optional parameter for a variety of methods. Consider to use named parameters to avoid confusion with changed parameter order. -Message message = await bot.SendTextMessageAsync(\n- _fixture.SupergroupChat.Id,\n- \"Please click on *Notify* button.\",\n- cancellationToken);\n+Message message = await bot.SendTextMessageAsync(\n+ chatId: _fixture.SupergroupChat.Id,\n+ text: \"Please click on *Notify* button.\",\n+ messageThreadId: threadId,\n+ cancellationToken: cancellationToken);","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Topics in Groups","id":"190","title":"Topics in Groups"},"191":{"body":"Old InputMedia* class hierarchy poorly reflected actual file-related APIs. We removed old hierarchy of InputFile related classes such as InputOnlineFile, InputTelegramFile, InputFileStream, etc., and also removed all implicit casts to them. From now on you should explicitly specify one of file types: InputFileStream for Stream content, InputFileUrl for URL and InputFileId if you want to use existing file_id. For convenience the base InputType class has factory methods to create the correct types: InputFile.FromStream(Stream stream, string? fileName = default) for streams InputFile.FromString(string urlOrFileId) for URLs or file ids InputFile.FromUri(Uri url) - for URLs as strings InputFile.FromUri(string url) - for URLs as URIs InputFile.FromFileId(string fileId) - for file ids The migration scheme looks like that: Previous method New method new InputTelegramType(string) InputFile.FromId(string), InputFile.FromString(string) new InputTelegramType(Stream, string?) InputFile.FromStream(Stream, string?) new InputFileStream(Stream) InputFile.FromStream(Stream) new InputOnlineFile(string) InputFile.FromId(string), InputFile.FromString(string), InputFile.FromString(string), InputFile.FromUrl(string), InputFile.FromUrl(Uri) new InputOnlineFile(Stream, string?) InputFile.FromStream(Stream, string?) raw Stream InputFile.FromStream(Stream) raw string InputFile.FromString(string) raw URI InputFile.FromUrl(URI)","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » New InputFile Hierarchy","id":"191","title":"New InputFile Hierarchy"},"192":{"body":"Implicit conversion from ChatId to string was removed due to complaints and problems it caused. The migration path is to explicitly call ChatId.ToString() method.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » ChatId implicit conversion","id":"192","title":"ChatId implicit conversion"},"193":{"body":"All methods and types with animated, static and video sticker distinction were removed and replaced with a single set of sticker related methods per new Bot API updates: AddAnimatedStickerToSetAsync, AddStaticStickerToSetAsync, AddVideoStickerToSetAsync, etc. Remove the words Static, Animated and Video from sticker related methods in your code Associated emojies and masks were moved to a separate type InputSticker, use them there instead, consult the official Bot API docs for a more detailed information","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Stickers","id":"193","title":"Stickers"},"194":{"body":"Since .NET Core 3.1 LTS status is not officialy supported anymore we changed the target to netstandard2.0 and net6.0 instead. If you're using .NET Core 3.1 or .NET 5 runtimes you need to use the build for netstandard2.0 instead. If you relied on IAsyncEnumerable implementation of poller you need to move to .NET 6 instead.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » .NET Core 3.1 removed as a separate target framework","id":"194","title":".NET Core 3.1 removed as a separate target framework"},"195":{"body":"Message.Type returns MessageType.Animation when the message contains an Animation, use MessageType.Animation instead of MessageType.Document to check if the message contains an animation Property CanSendMediaMessages was removed from the types ChatMemberRestricted and ChatPermissions and replaced with more granular permissions, use them instead Removed method GetChatMembersCountAsync, use GetChatMemberCountAsync Removed method KickChatMemberAsync, use BanChatMemberAsync Properties and types VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted removed, use methods and types which start with Video* instead All propties with the word Thumb in them were renamed to contain the word Thumbnail per new Bot API updates A new type InlineQueryResultsButton is used instead of SwitchPmText and SwitchPmParameter properties, consult the official Bot API docs","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Other changes","id":"195","title":"Other changes"},"196":{"body":"Most breaking changes in v18 come from new Bot API changes, such as: In Bot API 6.0 voice_chat* related message properties were deprecated in favour of video_chat* with the same semantics and shape. With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. So static .WEBP *StickerSet* methods and requests were given a Static prefix. Removed untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class. As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long?. A new way of configuring the client. ApiRequestEventArgs contains full request data. Complete list of changes is available in CHANGELOG","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » Migration guide for version 18.0","id":"196","title":"Migration guide for version 18.0"},"197":{"body":"Telegram renamed voice_chat_* properties in the Message class and with video_chat_* onces so we replaced corresponding MessageType enum members with the new ones. Following properties in Message class and corresponding enum members in MessageType enum were changed: -VoiceChatScheduled\n-VoiceChatStarted\n-VoiceChatEnded\n-VoiceChatParticipantsInvited\n+VideoChatScheduled\n+VideoChatStarted\n+VideoChatEnded\n+VideoChatParticipantsInvited Also property CanManageVoiceChats in ChatMemberAdministrator and PromoteChatMemberRequest classes was renamed to CanManageVideoChats.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 1. Removal of VoiceChat* properties in Message object","id":"197","title":"1. Removal of VoiceChat* properties in Message object"},"198":{"body":"With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. We already used Animated and Video suffix for methods related to animated and video stickers so we decided to do the same for the static stickers: Classes CreateNewStickerSetRequest and AddStickerToSetRequest were renamed to CreateNewStaticStickerSetRequest and AddStaticStickerToSetRequest. Methods CreateNewStickerSetAsync and AddStickerToSetAsync where renamed to CreateStaticNewStickerSetAsync and AddStaticStickerToSetAsync.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 2. Renaming static sticker methods and classes","id":"198","title":"2. Renaming static sticker methods and classes"},"199":{"body":"The untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class were removed from the Bot API.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class","id":"199","title":"3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class"},"2":{"body":"This book is filled with ready-to-use snippets of code, but you can also find full project examples at our Telegram.Bot.Examples Github repository, featuring: Simple Console apps (long polling) Webhook ASP.NET example (with Controllers or Minimal APIs) Full-featured advanced solution Serverless Functions implementations","breadcrumbs":"Introduction » 🪄 More examples","id":"2","title":"🪄 More examples"},"20":{"body":"The message returned from this method represents a photo message because message.Photo has a value. Its value is a PhotoSize array with each element representing the same photo in different dimensions. If your bot needs to send this photo again at some point, it is recommended to store this array so you can reuse the file_id value. Here is how message.Photo array looks like in JSON: [ { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABCQawlb-dBXqBZUEAAEC\", \"file_size\": 1254, \"width\": 90, \"height\": 60 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABAKByRnc22RmBpUEAAEC\", \"file_size\": 16419, \"width\": 320, \"height\": 213 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABHezqGiNOz9yB5UEAAEC\", \"file_size\": 57865, \"width\": 640, \"height\": 426 }\n]","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo Message","id":"20","title":"Photo Message"},"200":{"body":"As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long? to accommodate this change.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 4. Lifting of the FileSize limit","id":"200","title":"4. Lifting of the FileSize limit"},"201":{"body":"Starting with this release client configuration parameters should be passed through TelegramBotClientOptions class. You need to create an instance of TelegramBotClientOptions and pass it to the client: using Telegram.Bot; var options = new TelegramBotClientOptions( token: \"sendMessage
method\", parseMode: ParseMode.Html, protectContent: true, replyParameters: update.Message.MessageId, replyMarkup: new InlineKeyboardMarkup( InlineKeyboardButton.WithUrl(\"Check sendMessage method\", \"https://core.telegram.org/bots/api#sendmessage\"))); The method SendTextMessageAsync of .NET Bot Client maps to sendMessage on Telegram's Bot API. This method sends a text message and returns the message object sent. text is written in HTML format and parseMode indicates that. You can also write in Markdown or plain text. By passing protectContent we prevent the message (and eventual media) to be copiable/forwardable elsewhere. It's a good idea to make it clear to a user the reason why the bot is sending this message and that's why we pass the user's message id for replyParameters. You have the option of specifying a replyMarkup when sending messages. Reply markups are explained in details later in this book. Here we used an Inline Keyboard Markup with a button that attaches to the message itself. Clicking that opens sendMessage method documentation in the browser.","breadcrumbs":"Beginner » Sending Messages » Text » Send Text Message","id":"15","title":"Send Text Message"},"150":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots only get messages at the moment they are posted. You could archive them all in a database for later retrieval.","breadcrumbs":"Frequently Asked Questions » 8. How to fetch previous messages?","id":"150","title":"8. How to fetch previous messages?"},"151":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots can only get the list of admins (GetChatAdministratorsAsync) or detail about one specific member (GetChatMemberAsync) Alternatively, you can keep track of users by observing new messages in a chat and saving user info into a database.","breadcrumbs":"Frequently Asked Questions » 9. How to fetch a list of all users in chat?","id":"151","title":"9. How to fetch a list of all users in chat?"},"152":{"body":"You can't. Bots can only send private messages to users that have already initiated a private chat with your bot.","breadcrumbs":"Frequently Asked Questions » 10. How to send a private message to some random user?","id":"152","title":"10. How to send a private message to some random user?"},"153":{"body":"You would have received an update.MyChatMember with NewChatMember.Status == ChatMemberStatus.Kicked If you didn't record that info, you can try to SendChatActionAsync and see if it raises an exception.","breadcrumbs":"Frequently Asked Questions » 11. How to detect if a user blocked my bot?","id":"153","title":"11. How to detect if a user blocked my bot?"},"154":{"body":"Set the media.Caption (and media.ParseMode) on the first media","breadcrumbs":"Frequently Asked Questions » 12. How to set a caption to a media group (album)?","id":"154","title":"12. How to set a caption to a media group (album)?"},"155":{"body":"Either you can code a complex state machine workflow, saving where each user is currently in the discussion. Or you can just use YourEasyBot which makes sequential bots very simple to write... (or one of the other frameworks available for Telegram.Bot)","breadcrumbs":"Frequently Asked Questions » 13. How to write a bot that make questions/answers with users?","id":"155","title":"13. How to write a bot that make questions/answers with users?"},"156":{"body":"Pass a ParseMode.Html (or ParseMode.MarkDownV2) to argument parseMode. See formatting options . ⚠️ I highly recommend you choose HTML formatting because MarkDownV2 has A LOT of annoyingly reserved characters and you will regret it later.","breadcrumbs":"Frequently Asked Questions » 14. How to make font effects in message?","id":"156","title":"14. How to make font effects in message?"},"157":{"body":"I would recommend you make an ASP.NET webhook bot and host it on some WebApp hosting service. For example, Azure WebApp Service has a F1 Free plan including 1 GB disk, 1 GB ram, 60 minutes of daily cumulated active CPU usage (more than enough for most bots without heavy use) . And publishing to Azure is very easy from VS. A credit-card is necessary but you shouldn't get charged if you stay within quotas. Other cloud providers might also offer similar services.","breadcrumbs":"Frequently Asked Questions » 15. Where can I host my bot online for cheap/free?","id":"157","title":"15. Where can I host my bot online for cheap/free?"},"158":{"body":"See https://limits.tginfo.me for a list of limitations.","breadcrumbs":"Frequently Asked Questions » 16. Is there some limitation/maximum about feature X?","id":"158","title":"16. Is there some limitation/maximum about feature X?"},"159":{"body":"You can either do this via @BotFather (static entries) , or you can use SetMyCommandsAsync for more advanced settings ⚠️ This can only be filled with bot commands, starting with a / and containing only latin characters a-z_0-9","breadcrumbs":"Frequently Asked Questions » 17. How to populate the bot Menu button / commands list?","id":"159","title":"17. How to populate the bot Menu button / commands list?"},"16":{"body":"Almost all of the methods for sending messages return you the message you just sent. Let's have a look at this object. Add this statement after the previous code. Console.WriteLine( $\"{message.From.FirstName} sent message {message.MessageId} \" + $\"to chat {message.Chat.Id} at {message.Date}. \" + $\"It is a reply to message {message.ReplyToMessage.MessageId} \" + $\"and has {message.Entities.Length} message entities.\"); Output should look similar to this: Awesome bot sent message 123 to chat 123456789 at 8/21/18 11:25:09 AM. It is a reply to message 122 and has 2 message entities. There are a few things to note. Date and time is in UTC format and not your local timezone. Convert it to local time by calling message.Date.ToLocalTime() method. Message Entity refers to those formatted parts of the text: all the parameters in bold and sendMessage in mono-width font. Property message.Entities holds the formatting information and message.EntityValues gives you the actual value. For example, in the message we just sent: message.Entities.First().Type == MessageEntityType.Bold\nmessage.EntityValues.First() == \"all the parameters\" Try putting a breakpoint in the code to examine all the properties on a message objects you get.","breadcrumbs":"Beginner » Sending Messages » Text » The Sent Message","id":"16","title":"The Sent Message"},"160":{"body":"You should specify all update types including ChatMember in AllowedUpdates array on StartReceiving:ReceiverOptions or SetWebhookAsync","breadcrumbs":"Frequently Asked Questions » 18. How to receive ChatMember updates?","id":"160","title":"18. How to receive ChatMember updates?"},"161":{"body":"Pass true into StartReceiving:ReceiverOptions:DropPendingUpdates or SetWebhookAsync:dropPendingUpdates Alternatively, you can call await bot.DropPendingUpdatesAsync() before polling or using bot.OnUpdate .","breadcrumbs":"Frequently Asked Questions » 19. How to get rid of past updates when I restart my bot?","id":"161","title":"19. How to get rid of past updates when I restart my bot?"},"162":{"body":"Make sure you await until the end of the send method before closing the file (a \"using\" clause would close the file on leaving the current { scope } If you just filled a MemoryStream, make sure to rewind it to the beginning with ms.Position = 0; before sending If you send a media group, make sure you specify different filenames on InputFile.FromStream","breadcrumbs":"Frequently Asked Questions » 20. Difficulties to upload & send a file/media?","id":"162","title":"20. Difficulties to upload & send a file/media?"},"163":{"body":"Medias in a media group are received as separate consecutive messages having the same MediaGroupId property. You should collect them progressively as you receive those messages. There is no way to know how many medias are in the album, so: look for consecutive messages in that chat with same MediaGroupId and stop when it's not the same stop after 10 media in the group (maximum) use a timeout of a few seconds not receiving new messages in that chat to determine the end","breadcrumbs":"Frequently Asked Questions » 21. How to fetch all medias from an album/media group ?","id":"163","title":"21. How to fetch all medias from an album/media group ?"},"164":{"body":"⚠️ It costs about ~$5,000 !! 😱 First you need to buy a reserved username on Fragment . Then you need to pay an additional upgrade fee of 1K TON to apply that username to your bot. Finally, your bot can now post custom emojis using specific HTML or Markdown syntax (or entity). To post to a specific group, there is an alternative solution: Have premium members boost your group to Level 4. Then you can assign a custom emoji pack to your group that your members AND bots can use freely in group messages.","breadcrumbs":"Frequently Asked Questions » 22. How to send a custom emoji❓","id":"164","title":"22. How to send a custom emoji❓"},"165":{"body":"A new lead developer (Wizou) is now in charge of the library and commits to reduce code-breaking changes in the future. Version 21.x of the library have been much improved to facilitate migration from previous versions of the library, and include a lot of helpers/implicit operators to simplify your code.","breadcrumbs":"Frequently Asked Questions » 23. How to upgrade my existing code? You keep breaking compatibility!","id":"165","title":"23. How to upgrade my existing code? You keep breaking compatibility!"},"166":{"body":"You can call API methods (like sending messages) from several instances in parallel BUT only one instance can call method GetUpdates (or else you will receive Telegram API Error 409: Conflict: terminated by other getUpdates request )","breadcrumbs":"Frequently Asked Questions » 24. Can I use several apps/instance to manage my bot?","id":"166","title":"24. Can I use several apps/instance to manage my bot?"},"167":{"body":"You can't with Bot API but it's possible with WTelegramBot . Alternatively, you could store in database the mapping of UserId<->Username. Remember that not every user has a username.","breadcrumbs":"Frequently Asked Questions » 25. How do I get the user id from a username?","id":"167","title":"25. How do I get the user id from a username?"},"168":{"body":"Your bot has to be added as administrator of the channel. You will then receive the messages as update.ChannelPost or update.EditedChannelPost.","breadcrumbs":"Frequently Asked Questions » 26. How to receive messages from channels?","id":"168","title":"26. How to receive messages from channels?"},"169":{"body":"The first time, you will send the media with a stream (upload). Next times, you will use its FileId : var sent = await bot.SendVideoAsync(chatId, stream, ....);\nvar fileId = sent.Video.FileId // next times:\nawait bot.SendVideoAsync(chatId2, fileId, ...); For photos, use sent.Photo[^1].FileId","breadcrumbs":"Frequently Asked Questions » 27. How to sent the same media multiple times","id":"169","title":"27. How to sent the same media multiple times"},"17":{"body":"You can provide the source file for almost all multimedia messages (e.g. photo, video) in 3 ways: Uploading a file with the HTTP request HTTP URL for Telegram to get a file from the internet file_id of an existing file on Telegram servers ( recommended ) Examples in this section show all three. You will learn more about them later on when we discuss file upload and download .","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo and Sticker Messages","id":"17","title":"Photo and Sticker Messages"},"170":{"body":"Feel free to join our Telegram group and ask your question there","breadcrumbs":"Frequently Asked Questions » This FAQ doesn't have my question on it","id":"170","title":"This FAQ doesn't have my question on it"},"171":{"body":"Migrate to v21.* Migrate to v19.* Migrate to v18.* Migrate to v17.* Migrate to v14.*","breadcrumbs":"Migration guides to newer versions » Migration guides to newer versions of the library","id":"171","title":"Migration guides to newer versions of the library"},"172":{"body":"Important notes: Don't bother about version 20, migrate directly to version 21.* You won't find this version on Nuget: See this guide to install it in your programs . Version 21.8 supports Bot API 7.8 (including Telegram Stars payments ) Library is now based on System.Text.Json and doesn't depend on NewtonsoftJson anymore. ( See below )","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Migration guide for version 21.x","id":"172","title":"Migration guide for version 21.x"},"173":{"body":"That parameter was renamed and you can still pass a messageId for simple replies. Or you can pass a ReplyParameters structure for more advanced reply configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter replyToMessageId: → replyParameters:","id":"173","title":"Renamed parameter replyToMessageId: → replyParameters:"},"174":{"body":"That parameter was renamed and you can still pass true to disable web preview. Or you can pass a LinkPreviewOptions structure for more precise preview configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter disableWebPagePreview: → linkPreviewOptions:","id":"174","title":"Renamed parameter disableWebPagePreview: → linkPreviewOptions:"},"175":{"body":"Many boolean parameters or fields are now simply of type bool. In most cases, it shouldn't impact your existing code, or rather simplify it. Previously null values are now just false.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed bool? → bool","id":"175","title":"Changed bool? → bool"},"176":{"body":"When you don't need to specify a ParseMode, just pass default or ParseMode.None.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed ParseMode? → ParseMode","id":"176","title":"Changed ParseMode? → ParseMode"},"177":{"body":"We added/restored features & implicit conversions that make your code simpler: InputFile: just pass a string/Stream for file_id/url/stream content (as was possible in previous versions of Telegram.Bot) InputMedia*: just pass an InputFile when you don't need to associate caption or such MessageId: auto-converts to/from int (and also from Message) ReactionType: just pass a string when you want to send an emoji ReactionType: just pass a long when you want to send a custom emoji (id) Some other obvious implicit conversion operators for structures containing a single property No more enforcing init; properties, so you can adjust the content of fields as you wish or modify a structure returned by the API (before passing it back to the API if you want) No more JSON \"required properties\" during deserialization, so your old saved JSON files won't break if a field is added/renamed. Restored some MessageType enum values that were removed (renamed) recently (easier compatibility)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Better backward-compatibility and simplification of code","id":"177","title":"Better backward-compatibility and simplification of code"},"178":{"body":"This class hierarchy was introduced in Bot API 7.0 and broke existing code and added unnecessary complexity. This was removed in our library v21 and you will just receive directly a Message (as before) . To identify an \"inaccessible message\", you can just check message.Type == MessageType.Unknown or message.Date == default.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » MaybeInaccessibleMessage","id":"178","title":"MaybeInaccessibleMessage"},"179":{"body":"In previous versions, the big Chat structure contained many fields that were filled only after a call to GetChatAsync. This structure is now split into Chat and ChatFullInfo structures. The new Chat structure contains only common fields that are always filled. The new ChatFullInfo structure inherits from Chat and is returned only by GetChatAsync method, with all the extra fields.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Chat and ChatFullInfo","id":"179","title":"Chat and ChatFullInfo"},"18":{"body":"send photo method photo tests Sending a photo is simple. Here is an example: var message = await bot.SendPhotoAsync(chatId, \"https://telegrambots.github.io/book/docs/photo-ara.jpg\", caption: \"Ara bird. Source: Pixabay\", parseMode: ParseMode.Html); photo message","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo","id":"18","title":"Photo"},"180":{"body":"Request structures (types ending with Request) are NOT the recommended way to use the library in your projects. They are to be considered as low-level raw access to Bot API structures for advanced programmers, and might change/break at any time in the future. If you have existing code using them, you can use the MakeRequestAsync method to send those requests. (Other methods based on those requests will be removed soon)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Request structures","id":"180","title":"Request structures"},"181":{"body":"To make a payment in Telegram Stars with SendInvoiceAsync, set the following parameters: providerToken: null or \"\" currency: \"XTR\" prices: with a single price no tip amounts","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Payments with Telegram Stars","id":"181","title":"Payments with Telegram Stars"},"182":{"body":"The library now uses System.Text.Json instead of NewtonsoftJson. To make it work in your ASP.NET projects, you should now: Remove package Microsoft.AspNetCore.Mvc.NewtonsoftJson from your project dependencies Follow our Webhook page to configure your web app correctly","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Webhooks with System.Text.Json","id":"182","title":"Webhooks with System.Text.Json"},"183":{"body":"SendPollAsync now expect an array of InputPollOption instead of string. But we added an implicit conversion from string to InputPollOption, so the change is minimal: // before:\nawait bot.SendPollAsync(chatId, \"question\", new[] { \"answer1\", \"answer2\" });\n// after:\nawait bot.SendPollAsync(chatId, \"question\", new InputPollOption[] { \"answer1\", \"answer2\" });","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » InputPollOption in SendPollAsync","id":"183","title":"InputPollOption in SendPollAsync"},"184":{"body":"You can now specify a global CancellationToken directly in TelegramBotClient constructor. This way, you won't need to pass a cancellationToken to every method call after that (if you just need one single cancellation token for stopping your bot)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Global cancellation token (v21.2)","id":"184","title":"Global cancellation token (v21.2)"},"185":{"body":"warning That's a change of behaviour, but most of you will probably welcome this change If you forgot to wrap your HandleUpdateAsync code in a big try..catch, and your code happen to throw an exception, this would previously stop the polling completely. Now the Polling system will catch your exceptions, pass them to your HandleErrorAsync method and continue the polling . In previous versions of the library: ReceiveAsync would throw out the exception (therefore stopping the polling) StartReceiving would pass the exception to HandlePollingErrorAsync and silently stop the polling If you still want the previous behaviour, have your HandleErrorAsync start like this: Task HandleErrorAsync(ITelegramBotClient bot, Exception ex, HandleErrorSource source, CancellationToken ct)\n{ if (source is HandleErrorSource.HandleUpdateError) throw ex; ...","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Polling system now catch exceptions in your HandleUpdate code (v21.3)","id":"185","title":"Polling system now catch exceptions in your HandleUpdate code (v21.3)"},"186":{"body":"When replying to a message, you can now simply pass a Message for replyParameters: rather than a Message.MessageId Update.AllTypes is a constant array containing all UpdateTypes. You can pass it for the allowedUpdates: parameter (GetUpdatesAsync/SetWebhookAsync) Message has now 2 extensions methods: .ToHtml() and .ToMarkdown() to convert the message text/caption and their entities into a simple Html or Markdown string. You can also use methods Markdown.Escape() and HtmlText.Escape() to sanitize reserved characters from strings Reply/Inline Keyboard Markup now have construction methods to simplify building keyboards dynamically: var replyMarkup = new InlineKeyboardMarkup() .AddButton(InlineKeyboardButton.WithUrl(\"Link to Repository\", \"https://github.com/TelegramBots/Telegram.Bot\")) .AddNewRow().AddButton(\"callback\").AddButton(\"caption\", \"data\") .AddNewRow(\"with\", \"three\", \"buttons\") .AddNewRow().AddButtons(\"A\", \"B\", InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(\"switch\")); Same for ReplyKeyboardMarkup (and you can use new ReplyKeyboardMarkup(true) to resize keyboard) As previously announced , the Request-typed methods are gone. But you can still send Request structures via the MakeRequestAsync method.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » New helpers/extensions to simplify your code (v21.5)","id":"186","title":"New helpers/extensions to simplify your code (v21.5)"},"187":{"body":"Instead of StartReceiving/ReceiveAsync system, you can now simply set 2 or 3 events on the botClient: bot.OnMessage += ... to receive Message updates bot.OnUpdate += ... to receive other updates (or all updates if you don't set OnMessage) bot.OnError += ... to handle errors/exceptions during polling or your handlers Note: Second argument to OnMessage event specifies which kind of update it was ( edited , channel or business message?) When you assign those events, polling starts automatically, you don't have anything to do. Polling will stop when you remove (-=) your events, or when you cancel the global cancellation token You can also use await bot.DropPendingUpdatesAsync() before setting those events to ignore past updates. The Console example project has been updated to demonstrate these events.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Simplified polling with events (v21.7)","id":"187","title":"Simplified polling with events (v21.7)"},"188":{"body":"If Telegram servers fail on your API call with this error and ask you to to retry in less than 60 seconds, TelegramBotClient will now automatically wait for the requested delay and retry sending the same request up to 3 times. This is configurable using Options on the constructor: using var cts = new CancellationTokenSource();\nvar options = new TelegramBotClientOptions(token) { RetryThreshold = 120, RetryCount = 2 };\nvar bot = new TelegramBotClient(options, cancellationToken: cts.Token); *️⃣ This is a change of behavior compared to previous versions, but probably a welcome one. To disable this system and keep the same behavior as previous versions, use RetryThreshold = 0 Notes for advanced users: If this happens while uploading files (InputFile streams), the streams will be reset to their start position in order to be sent again If your streams are non-seekable (no problem with MemoryStream/FileStream) , the full HTTP request to Bot API will be buffered before the first sending (so it can lead to a temporary use of memory if you're sending big files)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)","id":"188","title":"Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)"},"189":{"body":"","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Migration guide for version 19.0","id":"189","title":"Migration guide for version 19.0"},"19":{"body":"Multimedia messages can optionally have a caption attached to them. Here we sent a caption in HTML format. A user can click on Pixabay in the caption to open its URL in the browser. Similar to message entities discussed before, caption entities on Message object are the result of parsing formatted(Markdown or HTML) caption text. Try inspecting these properties in debug mode: message.Caption: caption in plain text without formatting message.CaptionEntities: info about special entities in the caption message.CaptionEntityValues: text values of mentioned entities","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Caption","id":"19","title":"Caption"},"190":{"body":"New topics functionality allow bots interact with users in topic specified by messageThreadId parameter. We try to keep our Bot API implementation as close to Telegram Bot API as possible. This means, that the new messageThreadId now the first optional parameter for a variety of methods. Consider to use named parameters to avoid confusion with changed parameter order. -Message message = await bot.SendTextMessageAsync(\n- _fixture.SupergroupChat.Id,\n- \"Please click on *Notify* button.\",\n- cancellationToken);\n+Message message = await bot.SendTextMessageAsync(\n+ chatId: _fixture.SupergroupChat.Id,\n+ text: \"Please click on *Notify* button.\",\n+ messageThreadId: threadId,\n+ cancellationToken: cancellationToken);","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Topics in Groups","id":"190","title":"Topics in Groups"},"191":{"body":"Old InputMedia* class hierarchy poorly reflected actual file-related APIs. We removed old hierarchy of InputFile related classes such as InputOnlineFile, InputTelegramFile, InputFileStream, etc., and also removed all implicit casts to them. From now on you should explicitly specify one of file types: InputFileStream for Stream content, InputFileUrl for URL and InputFileId if you want to use existing file_id. For convenience the base InputType class has factory methods to create the correct types: InputFile.FromStream(Stream stream, string? fileName = default) for streams InputFile.FromString(string urlOrFileId) for URLs or file ids InputFile.FromUri(Uri url) - for URLs as strings InputFile.FromUri(string url) - for URLs as URIs InputFile.FromFileId(string fileId) - for file ids The migration scheme looks like that: Previous method New method new InputTelegramType(string) InputFile.FromId(string), InputFile.FromString(string) new InputTelegramType(Stream, string?) InputFile.FromStream(Stream, string?) new InputFileStream(Stream) InputFile.FromStream(Stream) new InputOnlineFile(string) InputFile.FromId(string), InputFile.FromString(string), InputFile.FromString(string), InputFile.FromUrl(string), InputFile.FromUrl(Uri) new InputOnlineFile(Stream, string?) InputFile.FromStream(Stream, string?) raw Stream InputFile.FromStream(Stream) raw string InputFile.FromString(string) raw URI InputFile.FromUrl(URI)","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » New InputFile Hierarchy","id":"191","title":"New InputFile Hierarchy"},"192":{"body":"Implicit conversion from ChatId to string was removed due to complaints and problems it caused. The migration path is to explicitly call ChatId.ToString() method.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » ChatId implicit conversion","id":"192","title":"ChatId implicit conversion"},"193":{"body":"All methods and types with animated, static and video sticker distinction were removed and replaced with a single set of sticker related methods per new Bot API updates: AddAnimatedStickerToSetAsync, AddStaticStickerToSetAsync, AddVideoStickerToSetAsync, etc. Remove the words Static, Animated and Video from sticker related methods in your code Associated emojies and masks were moved to a separate type InputSticker, use them there instead, consult the official Bot API docs for a more detailed information","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Stickers","id":"193","title":"Stickers"},"194":{"body":"Since .NET Core 3.1 LTS status is not officialy supported anymore we changed the target to netstandard2.0 and net6.0 instead. If you're using .NET Core 3.1 or .NET 5 runtimes you need to use the build for netstandard2.0 instead. If you relied on IAsyncEnumerable implementation of poller you need to move to .NET 6 instead.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » .NET Core 3.1 removed as a separate target framework","id":"194","title":".NET Core 3.1 removed as a separate target framework"},"195":{"body":"Message.Type returns MessageType.Animation when the message contains an Animation, use MessageType.Animation instead of MessageType.Document to check if the message contains an animation Property CanSendMediaMessages was removed from the types ChatMemberRestricted and ChatPermissions and replaced with more granular permissions, use them instead Removed method GetChatMembersCountAsync, use GetChatMemberCountAsync Removed method KickChatMemberAsync, use BanChatMemberAsync Properties and types VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted removed, use methods and types which start with Video* instead All propties with the word Thumb in them were renamed to contain the word Thumbnail per new Bot API updates A new type InlineQueryResultsButton is used instead of SwitchPmText and SwitchPmParameter properties, consult the official Bot API docs","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Other changes","id":"195","title":"Other changes"},"196":{"body":"Most breaking changes in v18 come from new Bot API changes, such as: In Bot API 6.0 voice_chat* related message properties were deprecated in favour of video_chat* with the same semantics and shape. With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. So static .WEBP *StickerSet* methods and requests were given a Static prefix. Removed untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class. As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long?. A new way of configuring the client. ApiRequestEventArgs contains full request data. Complete list of changes is available in CHANGELOG","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » Migration guide for version 18.0","id":"196","title":"Migration guide for version 18.0"},"197":{"body":"Telegram renamed voice_chat_* properties in the Message class and with video_chat_* onces so we replaced corresponding MessageType enum members with the new ones. Following properties in Message class and corresponding enum members in MessageType enum were changed: -VoiceChatScheduled\n-VoiceChatStarted\n-VoiceChatEnded\n-VoiceChatParticipantsInvited\n+VideoChatScheduled\n+VideoChatStarted\n+VideoChatEnded\n+VideoChatParticipantsInvited Also property CanManageVoiceChats in ChatMemberAdministrator and PromoteChatMemberRequest classes was renamed to CanManageVideoChats.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 1. Removal of VoiceChat* properties in Message object","id":"197","title":"1. Removal of VoiceChat* properties in Message object"},"198":{"body":"With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. We already used Animated and Video suffix for methods related to animated and video stickers so we decided to do the same for the static stickers: Classes CreateNewStickerSetRequest and AddStickerToSetRequest were renamed to CreateNewStaticStickerSetRequest and AddStaticStickerToSetRequest. Methods CreateNewStickerSetAsync and AddStickerToSetAsync where renamed to CreateStaticNewStickerSetAsync and AddStaticStickerToSetAsync.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 2. Renaming static sticker methods and classes","id":"198","title":"2. Renaming static sticker methods and classes"},"199":{"body":"The untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class were removed from the Bot API.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class","id":"199","title":"3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class"},"2":{"body":"This book is filled with ready-to-use snippets of code, but you can also find full project examples at our Telegram.Bot.Examples Github repository, featuring: Simple Console apps (long polling) Webhook ASP.NET example (with Controllers or Minimal APIs) Full-featured advanced solution Serverless Functions implementations","breadcrumbs":"Introduction » 🪄 More examples","id":"2","title":"🪄 More examples"},"20":{"body":"The message returned from this method represents a photo message because message.Photo has a value. Its value is a PhotoSize array with each element representing the same photo in different dimensions. If your bot needs to send this photo again at some point, it is recommended to store this array so you can reuse the file_id value. Here is how message.Photo array looks like in JSON: [ { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABCQawlb-dBXqBZUEAAEC\", \"file_size\": 1254, \"width\": 90, \"height\": 60 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABAKByRnc22RmBpUEAAEC\", \"file_size\": 16419, \"width\": 320, \"height\": 213 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABHezqGiNOz9yB5UEAAEC\", \"file_size\": 57865, \"width\": 640, \"height\": 426 }\n]","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo Message","id":"20","title":"Photo Message"},"200":{"body":"As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long? to accommodate this change.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 4. Lifting of the FileSize limit","id":"200","title":"4. Lifting of the FileSize limit"},"201":{"body":"Starting with this release client configuration parameters should be passed through TelegramBotClientOptions class. You need to create an instance of TelegramBotClientOptions and pass it to the client: using Telegram.Bot; var options = new TelegramBotClientOptions( token: \"sendMessage
method\", parseMode: ParseMode.Html, protectContent: true, replyParameters: update.Message.MessageId, replyMarkup: new InlineKeyboardMarkup( InlineKeyboardButton.WithUrl(\"Check sendMessage method\", \"https://core.telegram.org/bots/api#sendmessage\"))); The method SendTextMessageAsync of .NET Bot Client maps to sendMessage on Telegram's Bot API. This method sends a text message and returns the message object sent. text is written in HTML format and parseMode indicates that. You can also write in Markdown or plain text. By passing protectContent we prevent the message (and eventual media) to be copiable/forwardable elsewhere. It's a good idea to make it clear to a user the reason why the bot is sending this message and that's why we pass the user's message id for replyParameters. You have the option of specifying a replyMarkup when sending messages. Reply markups are explained in details later in this book. Here we used an Inline Keyboard Markup with a button that attaches to the message itself. Clicking that opens sendMessage method documentation in the browser.","breadcrumbs":"Beginner » Sending Messages » Text » Send Text Message","id":"15","title":"Send Text Message"},"150":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots only get messages at the moment they are posted. You could archive them all in a database for later retrieval.","breadcrumbs":"Frequently Asked Questions » 8. How to fetch previous messages?","id":"150","title":"8. How to fetch previous messages?"},"151":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots can only get the list of admins (GetChatAdministratorsAsync) or detail about one specific member (GetChatMemberAsync) Alternatively, you can keep track of users by observing new messages in a chat and saving user info into a database.","breadcrumbs":"Frequently Asked Questions » 9. How to fetch a list of all users in chat?","id":"151","title":"9. How to fetch a list of all users in chat?"},"152":{"body":"You can't. Bots can only send private messages to users that have already initiated a private chat with your bot.","breadcrumbs":"Frequently Asked Questions » 10. How to send a private message to some random user?","id":"152","title":"10. How to send a private message to some random user?"},"153":{"body":"You would have received an update.MyChatMember with NewChatMember.Status == ChatMemberStatus.Kicked If you didn't record that info, you can try to SendChatActionAsync and see if it raises an exception.","breadcrumbs":"Frequently Asked Questions » 11. How to detect if a user blocked my bot?","id":"153","title":"11. How to detect if a user blocked my bot?"},"154":{"body":"Set the media.Caption (and media.ParseMode) on the first media","breadcrumbs":"Frequently Asked Questions » 12. How to set a caption to a media group (album)?","id":"154","title":"12. How to set a caption to a media group (album)?"},"155":{"body":"Either you can code a complex state machine workflow, saving where each user is currently in the discussion. Or you can just use YourEasyBot which makes sequential bots very simple to write... (or one of the other frameworks available for Telegram.Bot)","breadcrumbs":"Frequently Asked Questions » 13. How to write a bot that make questions/answers with users?","id":"155","title":"13. How to write a bot that make questions/answers with users?"},"156":{"body":"Pass a ParseMode.Html (or ParseMode.MarkDownV2) to argument parseMode. See formatting options . ⚠️ I highly recommend you choose HTML formatting because MarkDownV2 has A LOT of annoyingly reserved characters and you will regret it later.","breadcrumbs":"Frequently Asked Questions » 14. How to make font effects in message?","id":"156","title":"14. How to make font effects in message?"},"157":{"body":"I would recommend you make an ASP.NET webhook bot and host it on some WebApp hosting service. For example, Azure WebApp Service has a F1 Free plan including 1 GB disk, 1 GB ram, 60 minutes of daily cumulated active CPU usage (more than enough for most bots without heavy use) . And publishing to Azure is very easy from VS. A credit-card is necessary but you shouldn't get charged if you stay within quotas. Other cloud providers might also offer similar services.","breadcrumbs":"Frequently Asked Questions » 15. Where can I host my bot online for cheap/free?","id":"157","title":"15. Where can I host my bot online for cheap/free?"},"158":{"body":"See https://limits.tginfo.me for a list of limitations.","breadcrumbs":"Frequently Asked Questions » 16. Is there some limitation/maximum about feature X?","id":"158","title":"16. Is there some limitation/maximum about feature X?"},"159":{"body":"You can either do this via @BotFather (static entries) , or you can use SetMyCommandsAsync for more advanced settings ⚠️ This can only be filled with bot commands, starting with a / and containing only latin characters a-z_0-9","breadcrumbs":"Frequently Asked Questions » 17. How to populate the bot Menu button / commands list?","id":"159","title":"17. How to populate the bot Menu button / commands list?"},"16":{"body":"Almost all of the methods for sending messages return you the message you just sent. Let's have a look at this object. Add this statement after the previous code. Console.WriteLine( $\"{message.From.FirstName} sent message {message.MessageId} \" + $\"to chat {message.Chat.Id} at {message.Date}. \" + $\"It is a reply to message {message.ReplyToMessage.MessageId} \" + $\"and has {message.Entities.Length} message entities.\"); Output should look similar to this: Awesome bot sent message 123 to chat 123456789 at 8/21/18 11:25:09 AM. It is a reply to message 122 and has 2 message entities. There are a few things to note. Date and time is in UTC format and not your local timezone. Convert it to local time by calling message.Date.ToLocalTime() method. Message Entity refers to those formatted parts of the text: all the parameters in bold and sendMessage in mono-width font. Property message.Entities holds the formatting information and message.EntityValues gives you the actual value. For example, in the message we just sent: message.Entities.First().Type == MessageEntityType.Bold\nmessage.EntityValues.First() == \"all the parameters\" Try putting a breakpoint in the code to examine all the properties on a message objects you get.","breadcrumbs":"Beginner » Sending Messages » Text » The Sent Message","id":"16","title":"The Sent Message"},"160":{"body":"You should specify all update types including ChatMember in AllowedUpdates array on StartReceiving:ReceiverOptions or SetWebhookAsync","breadcrumbs":"Frequently Asked Questions » 18. How to receive ChatMember updates?","id":"160","title":"18. How to receive ChatMember updates?"},"161":{"body":"Pass true into StartReceiving:ReceiverOptions:DropPendingUpdates or SetWebhookAsync:dropPendingUpdates Alternatively, you can call await bot.DropPendingUpdatesAsync() before polling or using bot.OnUpdate .","breadcrumbs":"Frequently Asked Questions » 19. How to get rid of past updates when I restart my bot?","id":"161","title":"19. How to get rid of past updates when I restart my bot?"},"162":{"body":"Make sure you await until the end of the send method before closing the file (a \"using\" clause would close the file on leaving the current { scope } If you just filled a MemoryStream, make sure to rewind it to the beginning with ms.Position = 0; before sending If you send a media group, make sure you specify different filenames on InputFile.FromStream","breadcrumbs":"Frequently Asked Questions » 20. Difficulties to upload & send a file/media?","id":"162","title":"20. Difficulties to upload & send a file/media?"},"163":{"body":"Medias in a media group are received as separate consecutive messages having the same MediaGroupId property. You should collect them progressively as you receive those messages. There is no way to know how many medias are in the album, so: look for consecutive messages in that chat with same MediaGroupId and stop when it's not the same stop after 10 media in the group (maximum) use a timeout of a few seconds not receiving new messages in that chat to determine the end","breadcrumbs":"Frequently Asked Questions » 21. How to fetch all medias from an album/media group ?","id":"163","title":"21. How to fetch all medias from an album/media group ?"},"164":{"body":"⚠️ It costs about ~$5,000 !! 😱 First you need to buy a reserved username on Fragment . Then you need to pay an additional upgrade fee of 1K TON to apply that username to your bot. Finally, your bot can now post custom emojis using specific HTML or Markdown syntax (or entity). To post to a specific group, there is an alternative solution: Have premium members boost your group to Level 4. Then you can assign a custom emoji pack to your group that your members AND bots can use freely in group messages.","breadcrumbs":"Frequently Asked Questions » 22. How to send a custom emoji❓","id":"164","title":"22. How to send a custom emoji❓"},"165":{"body":"A new lead developer (Wizou) is now in charge of the library and commits to reduce code-breaking changes in the future. Version 21.x of the library have been much improved to facilitate migration from previous versions of the library, and include a lot of helpers/implicit operators to simplify your code.","breadcrumbs":"Frequently Asked Questions » 23. How to upgrade my existing code? You keep breaking compatibility!","id":"165","title":"23. How to upgrade my existing code? You keep breaking compatibility!"},"166":{"body":"You can call API methods (like sending messages) from several instances in parallel BUT only one instance can call method GetUpdates (or else you will receive Telegram API Error 409: Conflict: terminated by other getUpdates request )","breadcrumbs":"Frequently Asked Questions » 24. Can I use several apps/instance to manage my bot?","id":"166","title":"24. Can I use several apps/instance to manage my bot?"},"167":{"body":"You can't with Bot API but it's possible with WTelegramBot . Alternatively, you could store in database the mapping of UserId<->Username. Remember that not every user has a username.","breadcrumbs":"Frequently Asked Questions » 25. How do I get the user id from a username?","id":"167","title":"25. How do I get the user id from a username?"},"168":{"body":"Your bot has to be added as administrator of the channel. You will then receive the messages as update.ChannelPost or update.EditedChannelPost.","breadcrumbs":"Frequently Asked Questions » 26. How to receive messages from channels?","id":"168","title":"26. How to receive messages from channels?"},"169":{"body":"The first time, you will send the media with a stream (upload). Next times, you will use its FileId : var sent = await bot.SendVideoAsync(chatId, stream, ....);\nvar fileId = sent.Video.FileId // next times:\nawait bot.SendVideoAsync(chatId2, fileId, ...); For photos, use sent.Photo[^1].FileId","breadcrumbs":"Frequently Asked Questions » 27. How to sent the same media multiple times","id":"169","title":"27. How to sent the same media multiple times"},"17":{"body":"You can provide the source file for almost all multimedia messages (e.g. photo, video) in 3 ways: Uploading a file with the HTTP request HTTP URL for Telegram to get a file from the internet file_id of an existing file on Telegram servers ( recommended ) Examples in this section show all three. You will learn more about them later on when we discuss file upload and download .","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo and Sticker Messages","id":"17","title":"Photo and Sticker Messages"},"170":{"body":"Feel free to join our Telegram group and ask your question there","breadcrumbs":"Frequently Asked Questions » This FAQ doesn't have my question on it","id":"170","title":"This FAQ doesn't have my question on it"},"171":{"body":"Migrate to v21.* Migrate to v19.* Migrate to v18.* Migrate to v17.* Migrate to v14.*","breadcrumbs":"Migration guides to newer versions » Migration guides to newer versions of the library","id":"171","title":"Migration guides to newer versions of the library"},"172":{"body":"Important notes: Don't bother about version 20, migrate directly to version 21.* You won't find this version on Nuget: See this guide to install it in your programs . Version 21.8 supports Bot API 7.8 (including Telegram Stars payments ) Library is now based on System.Text.Json and doesn't depend on NewtonsoftJson anymore. ( See below )","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Migration guide for version 21.x","id":"172","title":"Migration guide for version 21.x"},"173":{"body":"That parameter was renamed and you can still pass a messageId for simple replies. Or you can pass a ReplyParameters structure for more advanced reply configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter replyToMessageId: → replyParameters:","id":"173","title":"Renamed parameter replyToMessageId: → replyParameters:"},"174":{"body":"That parameter was renamed and you can still pass true to disable web preview. Or you can pass a LinkPreviewOptions structure for more precise preview configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter disableWebPagePreview: → linkPreviewOptions:","id":"174","title":"Renamed parameter disableWebPagePreview: → linkPreviewOptions:"},"175":{"body":"Many boolean parameters or fields are now simply of type bool. In most cases, it shouldn't impact your existing code, or rather simplify it. Previously null values are now just false.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed bool? → bool","id":"175","title":"Changed bool? → bool"},"176":{"body":"When you don't need to specify a ParseMode, just pass default or ParseMode.None.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed ParseMode? → ParseMode","id":"176","title":"Changed ParseMode? → ParseMode"},"177":{"body":"We added/restored features & implicit conversions that make your code simpler: InputFile: just pass a string/Stream for file_id/url/stream content (as was possible in previous versions of Telegram.Bot) InputMedia*: just pass an InputFile when you don't need to associate caption or such MessageId: auto-converts to/from int (and also from Message) ReactionType: just pass a string when you want to send an emoji ReactionType: just pass a long when you want to send a custom emoji (id) Some other obvious implicit conversion operators for structures containing a single property No more enforcing init; properties, so you can adjust the content of fields as you wish or modify a structure returned by the API (before passing it back to the API if you want) No more JSON \"required properties\" during deserialization, so your old saved JSON files won't break if a field is added/renamed. Restored some MessageType enum values that were removed (renamed) recently (easier compatibility)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Better backward-compatibility and simplification of code","id":"177","title":"Better backward-compatibility and simplification of code"},"178":{"body":"This class hierarchy was introduced in Bot API 7.0 and broke existing code and added unnecessary complexity. This was removed in our library v21 and you will just receive directly a Message (as before) . To identify an \"inaccessible message\", you can just check message.Type == MessageType.Unknown or message.Date == default.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » MaybeInaccessibleMessage","id":"178","title":"MaybeInaccessibleMessage"},"179":{"body":"In previous versions, the big Chat structure contained many fields that were filled only after a call to GetChatAsync. This structure is now split into Chat and ChatFullInfo structures. The new Chat structure contains only common fields that are always filled. The new ChatFullInfo structure inherits from Chat and is returned only by GetChatAsync method, with all the extra fields.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Chat and ChatFullInfo","id":"179","title":"Chat and ChatFullInfo"},"18":{"body":"send photo method photo tests Sending a photo is simple. Here is an example: var message = await bot.SendPhotoAsync(chatId, \"https://telegrambots.github.io/book/docs/photo-ara.jpg\", caption: \"Ara bird. Source: Pixabay\", parseMode: ParseMode.Html); photo message","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo","id":"18","title":"Photo"},"180":{"body":"Request structures (types ending with Request) are NOT the recommended way to use the library in your projects. They are to be considered as low-level raw access to Bot API structures for advanced programmers, and might change/break at any time in the future. If you have existing code using them, you can use the MakeRequestAsync method to send those requests. (Other methods based on those requests will be removed soon)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Request structures","id":"180","title":"Request structures"},"181":{"body":"To make a payment in Telegram Stars with SendInvoiceAsync, set the following parameters: providerToken: null or \"\" currency: \"XTR\" prices: with a single price no tip amounts","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Payments with Telegram Stars","id":"181","title":"Payments with Telegram Stars"},"182":{"body":"The library now uses System.Text.Json instead of NewtonsoftJson. To make it work in your ASP.NET projects, you should now: Remove package Microsoft.AspNetCore.Mvc.NewtonsoftJson from your project dependencies Follow our Webhook page to configure your web app correctly","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Webhooks with System.Text.Json","id":"182","title":"Webhooks with System.Text.Json"},"183":{"body":"SendPollAsync now expect an array of InputPollOption instead of string. But we added an implicit conversion from string to InputPollOption, so the change is minimal: // before:\nawait bot.SendPollAsync(chatId, \"question\", new[] { \"answer1\", \"answer2\" });\n// after:\nawait bot.SendPollAsync(chatId, \"question\", new InputPollOption[] { \"answer1\", \"answer2\" });","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » InputPollOption in SendPollAsync","id":"183","title":"InputPollOption in SendPollAsync"},"184":{"body":"You can now specify a global CancellationToken directly in TelegramBotClient constructor. This way, you won't need to pass a cancellationToken to every method call after that (if you just need one single cancellation token for stopping your bot)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Global cancellation token (v21.2)","id":"184","title":"Global cancellation token (v21.2)"},"185":{"body":"warning That's a change of behaviour, but most of you will probably welcome this change If you forgot to wrap your HandleUpdateAsync code in a big try..catch, and your code happen to throw an exception, this would previously stop the polling completely. Now the Polling system will catch your exceptions, pass them to your HandleErrorAsync method and continue the polling . In previous versions of the library: ReceiveAsync would throw out the exception (therefore stopping the polling) StartReceiving would pass the exception to HandlePollingErrorAsync and silently stop the polling If you still want the previous behaviour, have your HandleErrorAsync start like this: Task HandleErrorAsync(ITelegramBotClient bot, Exception ex, HandleErrorSource source, CancellationToken ct)\n{ if (source is HandleErrorSource.HandleUpdateError) throw ex; ...","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Polling system now catch exceptions in your HandleUpdate code (v21.3)","id":"185","title":"Polling system now catch exceptions in your HandleUpdate code (v21.3)"},"186":{"body":"When replying to a message, you can now simply pass a Message for replyParameters: rather than a Message.MessageId Update.AllTypes is a constant array containing all UpdateTypes. You can pass it for the allowedUpdates: parameter (GetUpdatesAsync/SetWebhookAsync) Message has now 2 extensions methods: .ToHtml() and .ToMarkdown() to convert the message text/caption and their entities into a simple Html or Markdown string. You can also use methods Markdown.Escape() and HtmlText.Escape() to sanitize reserved characters from strings Reply/Inline Keyboard Markup now have construction methods to simplify building keyboards dynamically: var replyMarkup = new InlineKeyboardMarkup() .AddButton(InlineKeyboardButton.WithUrl(\"Link to Repository\", \"https://github.com/TelegramBots/Telegram.Bot\")) .AddNewRow().AddButton(\"callback\").AddButton(\"caption\", \"data\") .AddNewRow(\"with\", \"three\", \"buttons\") .AddNewRow().AddButtons(\"A\", \"B\", InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(\"switch\")); Same for ReplyKeyboardMarkup (and you can use new ReplyKeyboardMarkup(true) to resize keyboard) As previously announced , the Request-typed methods are gone. But you can still send Request structures via the MakeRequestAsync method.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » New helpers/extensions to simplify your code (v21.5)","id":"186","title":"New helpers/extensions to simplify your code (v21.5)"},"187":{"body":"Instead of StartReceiving/ReceiveAsync system, you can now simply set 2 or 3 events on the botClient: bot.OnMessage += ... to receive Message updates bot.OnUpdate += ... to receive other updates (or all updates if you don't set OnMessage) bot.OnError += ... to handle errors/exceptions during polling or your handlers Note: Second argument to OnMessage event specifies which kind of update it was ( edited , channel or business message?) When you assign those events, polling starts automatically, you don't have anything to do. Polling will stop when you remove (-=) your events, or when you cancel the global cancellation token You can also use await bot.DropPendingUpdatesAsync() before setting those events to ignore past updates. The Console example project has been updated to demonstrate these events.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Simplified polling with events (v21.7)","id":"187","title":"Simplified polling with events (v21.7)"},"188":{"body":"If Telegram servers fail on your API call with this error and ask you to to retry in less than 60 seconds, TelegramBotClient will now automatically wait for the requested delay and retry sending the same request up to 3 times. This is configurable using Options on the constructor: using var cts = new CancellationTokenSource();\nvar options = new TelegramBotClientOptions(token) { RetryThreshold = 120, RetryCount = 2 };\nvar bot = new TelegramBotClient(options, cancellationToken: cts.Token); *️⃣ This is a change of behavior compared to previous versions, but probably a welcome one. To disable this system and keep the same behavior as previous versions, use RetryThreshold = 0 Notes for advanced users: If this happens while uploading files (InputFile streams), the streams will be reset to their start position in order to be sent again If your streams are non-seekable (no problem with MemoryStream/FileStream) , the full HTTP request to Bot API will be buffered before the first sending (so it can lead to a temporary use of memory if you're sending big files)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)","id":"188","title":"Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)"},"189":{"body":"","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Migration guide for version 19.0","id":"189","title":"Migration guide for version 19.0"},"19":{"body":"Multimedia messages can optionally have a caption attached to them. Here we sent a caption in HTML format. A user can click on Pixabay in the caption to open its URL in the browser. Similar to message entities discussed before, caption entities on Message object are the result of parsing formatted(Markdown or HTML) caption text. Try inspecting these properties in debug mode: message.Caption: caption in plain text without formatting message.CaptionEntities: info about special entities in the caption message.CaptionEntityValues: text values of mentioned entities","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Caption","id":"19","title":"Caption"},"190":{"body":"New topics functionality allow bots interact with users in topic specified by messageThreadId parameter. We try to keep our Bot API implementation as close to Telegram Bot API as possible. This means, that the new messageThreadId now the first optional parameter for a variety of methods. Consider to use named parameters to avoid confusion with changed parameter order. -Message message = await bot.SendTextMessageAsync(\n- _fixture.SupergroupChat.Id,\n- \"Please click on *Notify* button.\",\n- cancellationToken);\n+Message message = await bot.SendTextMessageAsync(\n+ chatId: _fixture.SupergroupChat.Id,\n+ text: \"Please click on *Notify* button.\",\n+ messageThreadId: threadId,\n+ cancellationToken: cancellationToken);","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Topics in Groups","id":"190","title":"Topics in Groups"},"191":{"body":"Old InputMedia* class hierarchy poorly reflected actual file-related APIs. We removed old hierarchy of InputFile related classes such as InputOnlineFile, InputTelegramFile, InputFileStream, etc., and also removed all implicit casts to them. From now on you should explicitly specify one of file types: InputFileStream for Stream content, InputFileUrl for URL and InputFileId if you want to use existing file_id. For convenience the base InputType class has factory methods to create the correct types: InputFile.FromStream(Stream stream, string? fileName = default) for streams InputFile.FromString(string urlOrFileId) for URLs or file ids InputFile.FromUri(Uri url) - for URLs as strings InputFile.FromUri(string url) - for URLs as URIs InputFile.FromFileId(string fileId) - for file ids The migration scheme looks like that: Previous method New method new InputTelegramType(string) InputFile.FromId(string), InputFile.FromString(string) new InputTelegramType(Stream, string?) InputFile.FromStream(Stream, string?) new InputFileStream(Stream) InputFile.FromStream(Stream) new InputOnlineFile(string) InputFile.FromId(string), InputFile.FromString(string), InputFile.FromString(string), InputFile.FromUrl(string), InputFile.FromUrl(Uri) new InputOnlineFile(Stream, string?) InputFile.FromStream(Stream, string?) raw Stream InputFile.FromStream(Stream) raw string InputFile.FromString(string) raw URI InputFile.FromUrl(URI)","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » New InputFile Hierarchy","id":"191","title":"New InputFile Hierarchy"},"192":{"body":"Implicit conversion from ChatId to string was removed due to complaints and problems it caused. The migration path is to explicitly call ChatId.ToString() method.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » ChatId implicit conversion","id":"192","title":"ChatId implicit conversion"},"193":{"body":"All methods and types with animated, static and video sticker distinction were removed and replaced with a single set of sticker related methods per new Bot API updates: AddAnimatedStickerToSetAsync, AddStaticStickerToSetAsync, AddVideoStickerToSetAsync, etc. Remove the words Static, Animated and Video from sticker related methods in your code Associated emojies and masks were moved to a separate type InputSticker, use them there instead, consult the official Bot API docs for a more detailed information","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Stickers","id":"193","title":"Stickers"},"194":{"body":"Since .NET Core 3.1 LTS status is not officialy supported anymore we changed the target to netstandard2.0 and net6.0 instead. If you're using .NET Core 3.1 or .NET 5 runtimes you need to use the build for netstandard2.0 instead. If you relied on IAsyncEnumerable implementation of poller you need to move to .NET 6 instead.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » .NET Core 3.1 removed as a separate target framework","id":"194","title":".NET Core 3.1 removed as a separate target framework"},"195":{"body":"Message.Type returns MessageType.Animation when the message contains an Animation, use MessageType.Animation instead of MessageType.Document to check if the message contains an animation Property CanSendMediaMessages was removed from the types ChatMemberRestricted and ChatPermissions and replaced with more granular permissions, use them instead Removed method GetChatMembersCountAsync, use GetChatMemberCountAsync Removed method KickChatMemberAsync, use BanChatMemberAsync Properties and types VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted removed, use methods and types which start with Video* instead All propties with the word Thumb in them were renamed to contain the word Thumbnail per new Bot API updates A new type InlineQueryResultsButton is used instead of SwitchPmText and SwitchPmParameter properties, consult the official Bot API docs","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Other changes","id":"195","title":"Other changes"},"196":{"body":"Most breaking changes in v18 come from new Bot API changes, such as: In Bot API 6.0 voice_chat* related message properties were deprecated in favour of video_chat* with the same semantics and shape. With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. So static .WEBP *StickerSet* methods and requests were given a Static prefix. Removed untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class. As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long?. A new way of configuring the client. ApiRequestEventArgs contains full request data. Complete list of changes is available in CHANGELOG","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » Migration guide for version 18.0","id":"196","title":"Migration guide for version 18.0"},"197":{"body":"Telegram renamed voice_chat_* properties in the Message class and with video_chat_* onces so we replaced corresponding MessageType enum members with the new ones. Following properties in Message class and corresponding enum members in MessageType enum were changed: -VoiceChatScheduled\n-VoiceChatStarted\n-VoiceChatEnded\n-VoiceChatParticipantsInvited\n+VideoChatScheduled\n+VideoChatStarted\n+VideoChatEnded\n+VideoChatParticipantsInvited Also property CanManageVoiceChats in ChatMemberAdministrator and PromoteChatMemberRequest classes was renamed to CanManageVideoChats.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 1. Removal of VoiceChat* properties in Message object","id":"197","title":"1. Removal of VoiceChat* properties in Message object"},"198":{"body":"With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. We already used Animated and Video suffix for methods related to animated and video stickers so we decided to do the same for the static stickers: Classes CreateNewStickerSetRequest and AddStickerToSetRequest were renamed to CreateNewStaticStickerSetRequest and AddStaticStickerToSetRequest. Methods CreateNewStickerSetAsync and AddStickerToSetAsync where renamed to CreateStaticNewStickerSetAsync and AddStaticStickerToSetAsync.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 2. Renaming static sticker methods and classes","id":"198","title":"2. Renaming static sticker methods and classes"},"199":{"body":"The untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class were removed from the Bot API.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class","id":"199","title":"3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class"},"2":{"body":"This book is filled with ready-to-use snippets of code, but you can also find full project examples at our Telegram.Bot.Examples Github repository, featuring: Simple Console apps (long polling) Webhook ASP.NET example (with Controllers or Minimal APIs) Full-featured advanced solution Serverless Functions implementations","breadcrumbs":"Introduction » 🪄 More examples","id":"2","title":"🪄 More examples"},"20":{"body":"The message returned from this method represents a photo message because message.Photo has a value. Its value is a PhotoSize array with each element representing the same photo in different dimensions. If your bot needs to send this photo again at some point, it is recommended to store this array so you can reuse the file_id value. Here is how message.Photo array looks like in JSON: [ { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABCQawlb-dBXqBZUEAAEC\", \"file_size\": 1254, \"width\": 90, \"height\": 60 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABAKByRnc22RmBpUEAAEC\", \"file_size\": 16419, \"width\": 320, \"height\": 213 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABHezqGiNOz9yB5UEAAEC\", \"file_size\": 57865, \"width\": 640, \"height\": 426 }\n]","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo Message","id":"20","title":"Photo Message"},"200":{"body":"As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long? to accommodate this change.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 4. Lifting of the FileSize limit","id":"200","title":"4. Lifting of the FileSize limit"},"201":{"body":"Starting with this release client configuration parameters should be passed through TelegramBotClientOptions class. You need to create an instance of TelegramBotClientOptions and pass it to the client: using Telegram.Bot; var options = new TelegramBotClientOptions( token: \"sendMessage
method\", parseMode: ParseMode.Html, protectContent: true, replyParameters: update.Message.MessageId, replyMarkup: new InlineKeyboardMarkup( InlineKeyboardButton.WithUrl(\"Check sendMessage method\", \"https://core.telegram.org/bots/api#sendmessage\"))); The method SendTextMessageAsync of .NET Bot Client maps to sendMessage on Telegram's Bot API. This method sends a text message and returns the message object sent. text is written in HTML format and parseMode indicates that. You can also write in Markdown or plain text. By passing protectContent we prevent the message (and eventual media) to be copiable/forwardable elsewhere. It's a good idea to make it clear to a user the reason why the bot is sending this message and that's why we pass the user's message id for replyParameters. You have the option of specifying a replyMarkup when sending messages. Reply markups are explained in details later in this book. Here we used an Inline Keyboard Markup with a button that attaches to the message itself. Clicking that opens sendMessage method documentation in the browser.","breadcrumbs":"Beginner » Sending Messages » Text » Send Text Message","id":"15","title":"Send Text Message"},"150":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots only get messages at the moment they are posted. You could archive them all in a database for later retrieval.","breadcrumbs":"Frequently Asked Questions » 8. How to fetch previous messages?","id":"150","title":"8. How to fetch previous messages?"},"151":{"body":"You can't with Bot API but it's possible with WTelegramBot . Normally, bots can only get the list of admins (GetChatAdministratorsAsync) or detail about one specific member (GetChatMemberAsync) Alternatively, you can keep track of users by observing new messages in a chat and saving user info into a database.","breadcrumbs":"Frequently Asked Questions » 9. How to fetch a list of all users in chat?","id":"151","title":"9. How to fetch a list of all users in chat?"},"152":{"body":"You can't. Bots can only send private messages to users that have already initiated a private chat with your bot.","breadcrumbs":"Frequently Asked Questions » 10. How to send a private message to some random user?","id":"152","title":"10. How to send a private message to some random user?"},"153":{"body":"You would have received an update.MyChatMember with NewChatMember.Status == ChatMemberStatus.Kicked If you didn't record that info, you can try to SendChatActionAsync and see if it raises an exception.","breadcrumbs":"Frequently Asked Questions » 11. How to detect if a user blocked my bot?","id":"153","title":"11. How to detect if a user blocked my bot?"},"154":{"body":"Set the media.Caption (and media.ParseMode) on the first media","breadcrumbs":"Frequently Asked Questions » 12. How to set a caption to a media group (album)?","id":"154","title":"12. How to set a caption to a media group (album)?"},"155":{"body":"Either you can code a complex state machine workflow, saving where each user is currently in the discussion. Or you can just use YourEasyBot which makes sequential bots very simple to write... (or one of the other frameworks available for Telegram.Bot)","breadcrumbs":"Frequently Asked Questions » 13. How to write a bot that make questions/answers with users?","id":"155","title":"13. How to write a bot that make questions/answers with users?"},"156":{"body":"Pass a ParseMode.Html (or ParseMode.MarkDownV2) to argument parseMode. See formatting options . ⚠️ I highly recommend you choose HTML formatting because MarkDownV2 has A LOT of annoyingly reserved characters and you will regret it later.","breadcrumbs":"Frequently Asked Questions » 14. How to make font effects in message?","id":"156","title":"14. How to make font effects in message?"},"157":{"body":"I would recommend you make an ASP.NET webhook bot and host it on some WebApp hosting service. For example, Azure WebApp Service has a F1 Free plan including 1 GB disk, 1 GB ram, 60 minutes of daily cumulated active CPU usage (more than enough for most bots without heavy use) . And publishing to Azure is very easy from VS. A credit-card is necessary but you shouldn't get charged if you stay within quotas. Other cloud providers might also offer similar services.","breadcrumbs":"Frequently Asked Questions » 15. Where can I host my bot online for cheap/free?","id":"157","title":"15. Where can I host my bot online for cheap/free?"},"158":{"body":"See https://limits.tginfo.me for a list of limitations.","breadcrumbs":"Frequently Asked Questions » 16. Is there some limitation/maximum about feature X?","id":"158","title":"16. Is there some limitation/maximum about feature X?"},"159":{"body":"You can either do this via @BotFather (static entries) , or you can use SetMyCommandsAsync for more advanced settings ⚠️ This can only be filled with bot commands, starting with a / and containing only latin characters a-z_0-9","breadcrumbs":"Frequently Asked Questions » 17. How to populate the bot Menu button / commands list?","id":"159","title":"17. How to populate the bot Menu button / commands list?"},"16":{"body":"Almost all of the methods for sending messages return you the message you just sent. Let's have a look at this object. Add this statement after the previous code. Console.WriteLine( $\"{message.From.FirstName} sent message {message.MessageId} \" + $\"to chat {message.Chat.Id} at {message.Date}. \" + $\"It is a reply to message {message.ReplyToMessage.MessageId} \" + $\"and has {message.Entities.Length} message entities.\"); Output should look similar to this: Awesome bot sent message 123 to chat 123456789 at 8/21/18 11:25:09 AM. It is a reply to message 122 and has 2 message entities. There are a few things to note. Date and time is in UTC format and not your local timezone. Convert it to local time by calling message.Date.ToLocalTime() method. Message Entity refers to those formatted parts of the text: all the parameters in bold and sendMessage in mono-width font. Property message.Entities holds the formatting information and message.EntityValues gives you the actual value. For example, in the message we just sent: message.Entities.First().Type == MessageEntityType.Bold\nmessage.EntityValues.First() == \"all the parameters\" Try putting a breakpoint in the code to examine all the properties on a message objects you get.","breadcrumbs":"Beginner » Sending Messages » Text » The Sent Message","id":"16","title":"The Sent Message"},"160":{"body":"You should specify all update types including ChatMember in AllowedUpdates array on StartReceiving:ReceiverOptions or SetWebhookAsync","breadcrumbs":"Frequently Asked Questions » 18. How to receive ChatMember updates?","id":"160","title":"18. How to receive ChatMember updates?"},"161":{"body":"Pass true into StartReceiving:ReceiverOptions:DropPendingUpdates or SetWebhookAsync:dropPendingUpdates Alternatively, you can call await bot.DropPendingUpdatesAsync() before polling or using bot.OnUpdate .","breadcrumbs":"Frequently Asked Questions » 19. How to get rid of past updates when I restart my bot?","id":"161","title":"19. How to get rid of past updates when I restart my bot?"},"162":{"body":"Make sure you await until the end of the send method before closing the file (a \"using\" clause would close the file on leaving the current { scope } If you just filled a MemoryStream, make sure to rewind it to the beginning with ms.Position = 0; before sending If you send a media group, make sure you specify different filenames on InputFile.FromStream","breadcrumbs":"Frequently Asked Questions » 20. Difficulties to upload & send a file/media?","id":"162","title":"20. Difficulties to upload & send a file/media?"},"163":{"body":"Medias in a media group are received as separate consecutive messages having the same MediaGroupId property. You should collect them progressively as you receive those messages. There is no way to know how many medias are in the album, so: look for consecutive messages in that chat with same MediaGroupId and stop when it's not the same stop after 10 media in the group (maximum) use a timeout of a few seconds not receiving new messages in that chat to determine the end","breadcrumbs":"Frequently Asked Questions » 21. How to fetch all medias from an album/media group ?","id":"163","title":"21. How to fetch all medias from an album/media group ?"},"164":{"body":"⚠️ It costs about ~$5,000 !! 😱 First you need to buy a reserved username on Fragment . Then you need to pay an additional upgrade fee of 1K TON to apply that username to your bot. Finally, your bot can now post custom emojis using specific HTML or Markdown syntax (or entity). To post to a specific group, there is an alternative solution: Have premium members boost your group to Level 4. Then you can assign a custom emoji pack to your group that your members AND bots can use freely in group messages.","breadcrumbs":"Frequently Asked Questions » 22. How to send a custom emoji❓","id":"164","title":"22. How to send a custom emoji❓"},"165":{"body":"A new lead developer (Wizou) is now in charge of the library and commits to reduce code-breaking changes in the future. Version 21.x of the library have been much improved to facilitate migration from previous versions of the library, and include a lot of helpers/implicit operators to simplify your code.","breadcrumbs":"Frequently Asked Questions » 23. How to upgrade my existing code? You keep breaking compatibility!","id":"165","title":"23. How to upgrade my existing code? You keep breaking compatibility!"},"166":{"body":"You can call API methods (like sending messages) from several instances in parallel BUT only one instance can call method GetUpdates (or else you will receive Telegram API Error 409: Conflict: terminated by other getUpdates request )","breadcrumbs":"Frequently Asked Questions » 24. Can I use several apps/instance to manage my bot?","id":"166","title":"24. Can I use several apps/instance to manage my bot?"},"167":{"body":"You can't with Bot API but it's possible with WTelegramBot . Alternatively, you could store in database the mapping of UserId<->Username. Remember that not every user has a username.","breadcrumbs":"Frequently Asked Questions » 25. How do I get the user id from a username?","id":"167","title":"25. How do I get the user id from a username?"},"168":{"body":"Your bot has to be added as administrator of the channel. You will then receive the messages as update.ChannelPost or update.EditedChannelPost.","breadcrumbs":"Frequently Asked Questions » 26. How to receive messages from channels?","id":"168","title":"26. How to receive messages from channels?"},"169":{"body":"The first time, you will send the media with a stream (upload). Next times, you will use its FileId : var sent = await bot.SendVideoAsync(chatId, stream, ....);\nvar fileId = sent.Video.FileId // next times:\nawait bot.SendVideoAsync(chatId2, fileId, ...); For photos, use sent.Photo[^1].FileId","breadcrumbs":"Frequently Asked Questions » 27. How to sent the same media multiple times","id":"169","title":"27. How to sent the same media multiple times"},"17":{"body":"You can provide the source file for almost all multimedia messages (e.g. photo, video) in 3 ways: Uploading a file with the HTTP request HTTP URL for Telegram to get a file from the internet file_id of an existing file on Telegram servers ( recommended ) Examples in this section show all three. You will learn more about them later on when we discuss file upload and download .","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo and Sticker Messages","id":"17","title":"Photo and Sticker Messages"},"170":{"body":"Feel free to join our Telegram group and ask your question there","breadcrumbs":"Frequently Asked Questions » This FAQ doesn't have my question on it","id":"170","title":"This FAQ doesn't have my question on it"},"171":{"body":"Migrate to v21.* Migrate to v19.* Migrate to v18.* Migrate to v17.* Migrate to v14.*","breadcrumbs":"Migration guides to newer versions » Migration guides to newer versions of the library","id":"171","title":"Migration guides to newer versions of the library"},"172":{"body":"Important notes: Don't bother about version 20, migrate directly to version 21.* You won't find this version on Nuget: See this guide to install it in your programs . Version 21.8 supports Bot API 7.8 (including Telegram Stars payments ) Library is now based on System.Text.Json and doesn't depend on NewtonsoftJson anymore. ( See below )","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Migration guide for version 21.x","id":"172","title":"Migration guide for version 21.x"},"173":{"body":"That parameter was renamed and you can still pass a messageId for simple replies. Or you can pass a ReplyParameters structure for more advanced reply configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter replyToMessageId: → replyParameters:","id":"173","title":"Renamed parameter replyToMessageId: → replyParameters:"},"174":{"body":"That parameter was renamed and you can still pass true to disable web preview. Or you can pass a LinkPreviewOptions structure for more precise preview configuration.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Renamed parameter disableWebPagePreview: → linkPreviewOptions:","id":"174","title":"Renamed parameter disableWebPagePreview: → linkPreviewOptions:"},"175":{"body":"Many boolean parameters or fields are now simply of type bool. In most cases, it shouldn't impact your existing code, or rather simplify it. Previously null values are now just false.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed bool? → bool","id":"175","title":"Changed bool? → bool"},"176":{"body":"When you don't need to specify a ParseMode, just pass default or ParseMode.None.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Changed ParseMode? → ParseMode","id":"176","title":"Changed ParseMode? → ParseMode"},"177":{"body":"We added/restored features & implicit conversions that make your code simpler: InputFile: just pass a string/Stream for file_id/url/stream content (as was possible in previous versions of Telegram.Bot) InputMedia*: just pass an InputFile when you don't need to associate caption or such MessageId: auto-converts to/from int (and also from Message) ReactionType: just pass a string when you want to send an emoji ReactionType: just pass a long when you want to send a custom emoji (id) Some other obvious implicit conversion operators for structures containing a single property No more enforcing init; properties, so you can adjust the content of fields as you wish or modify a structure returned by the API (before passing it back to the API if you want) No more JSON \"required properties\" during deserialization, so your old saved JSON files won't break if a field is added/renamed. Restored some MessageType enum values that were removed (renamed) recently (easier compatibility)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Better backward-compatibility and simplification of code","id":"177","title":"Better backward-compatibility and simplification of code"},"178":{"body":"This class hierarchy was introduced in Bot API 7.0 and broke existing code and added unnecessary complexity. This was removed in our library v21 and you will just receive directly a Message (as before) . To identify an \"inaccessible message\", you can just check message.Type == MessageType.Unknown or message.Date == default.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » MaybeInaccessibleMessage","id":"178","title":"MaybeInaccessibleMessage"},"179":{"body":"In previous versions, the big Chat structure contained many fields that were filled only after a call to GetChatAsync. This structure is now split into Chat and ChatFullInfo structures. The new Chat structure contains only common fields that are always filled. The new ChatFullInfo structure inherits from Chat and is returned only by GetChatAsync method, with all the extra fields.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Chat and ChatFullInfo","id":"179","title":"Chat and ChatFullInfo"},"18":{"body":"send photo method photo tests Sending a photo is simple. Here is an example: var message = await bot.SendPhotoAsync(chatId, \"https://telegrambots.github.io/book/docs/photo-ara.jpg\", caption: \"Ara bird. Source: Pixabay\", parseMode: ParseMode.Html); photo message","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo","id":"18","title":"Photo"},"180":{"body":"Request structures (types ending with Request) are NOT the recommended way to use the library in your projects. They are to be considered as low-level raw access to Bot API structures for advanced programmers, and might change/break at any time in the future. If you have existing code using them, you can use the MakeRequestAsync method to send those requests. (Other methods based on those requests will be removed soon)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Request structures","id":"180","title":"Request structures"},"181":{"body":"To make a payment in Telegram Stars with SendInvoiceAsync, set the following parameters: providerToken: null or \"\" currency: \"XTR\" prices: with a single price no tip amounts","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Payments with Telegram Stars","id":"181","title":"Payments with Telegram Stars"},"182":{"body":"The library now uses System.Text.Json instead of NewtonsoftJson. To make it work in your ASP.NET projects, you should now: Remove package Microsoft.AspNetCore.Mvc.NewtonsoftJson from your project dependencies Follow our Webhook page to configure your web app correctly","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Webhooks with System.Text.Json","id":"182","title":"Webhooks with System.Text.Json"},"183":{"body":"SendPollAsync now expect an array of InputPollOption instead of string. But we added an implicit conversion from string to InputPollOption, so the change is minimal: // before:\nawait bot.SendPollAsync(chatId, \"question\", new[] { \"answer1\", \"answer2\" });\n// after:\nawait bot.SendPollAsync(chatId, \"question\", new InputPollOption[] { \"answer1\", \"answer2\" });","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » InputPollOption in SendPollAsync","id":"183","title":"InputPollOption in SendPollAsync"},"184":{"body":"You can now specify a global CancellationToken directly in TelegramBotClient constructor. This way, you won't need to pass a cancellationToken to every method call after that (if you just need one single cancellation token for stopping your bot)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Global cancellation token (v21.2)","id":"184","title":"Global cancellation token (v21.2)"},"185":{"body":"warning That's a change of behaviour, but most of you will probably welcome this change If you forgot to wrap your HandleUpdateAsync code in a big try..catch, and your code happen to throw an exception, this would previously stop the polling completely. Now the Polling system will catch your exceptions, pass them to your HandleErrorAsync method and continue the polling . In previous versions of the library: ReceiveAsync would throw out the exception (therefore stopping the polling) StartReceiving would pass the exception to HandlePollingErrorAsync and silently stop the polling If you still want the previous behaviour, have your HandleErrorAsync start like this: Task HandleErrorAsync(ITelegramBotClient bot, Exception ex, HandleErrorSource source, CancellationToken ct)\n{ if (source is HandleErrorSource.HandleUpdateError) throw ex; ...","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Polling system now catch exceptions in your HandleUpdate code (v21.3)","id":"185","title":"Polling system now catch exceptions in your HandleUpdate code (v21.3)"},"186":{"body":"When replying to a message, you can now simply pass a Message for replyParameters: rather than a Message.MessageId Update.AllTypes is a constant array containing all UpdateTypes. You can pass it for the allowedUpdates: parameter (GetUpdatesAsync/SetWebhookAsync) Message has now 2 extensions methods: .ToHtml() and .ToMarkdown() to convert the message text/caption and their entities into a simple Html or Markdown string. You can also use methods Markdown.Escape() and HtmlText.Escape() to sanitize reserved characters from strings Reply/Inline Keyboard Markup now have construction methods to simplify building keyboards dynamically: var replyMarkup = new InlineKeyboardMarkup() .AddButton(InlineKeyboardButton.WithUrl(\"Link to Repository\", \"https://github.com/TelegramBots/Telegram.Bot\")) .AddNewRow().AddButton(\"callback\").AddButton(\"caption\", \"data\") .AddNewRow(\"with\", \"three\", \"buttons\") .AddNewRow().AddButtons(\"A\", \"B\", InlineKeyboardButton.WithSwitchInlineQueryCurrentChat(\"switch\")); Same for ReplyKeyboardMarkup (and you can use new ReplyKeyboardMarkup(true) to resize keyboard) As previously announced , the Request-typed methods are gone. But you can still send Request structures via the MakeRequestAsync method.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » New helpers/extensions to simplify your code (v21.5)","id":"186","title":"New helpers/extensions to simplify your code (v21.5)"},"187":{"body":"Instead of StartReceiving/ReceiveAsync system, you can now simply set 2 or 3 events on the botClient: bot.OnMessage += ... to receive Message updates bot.OnUpdate += ... to receive other updates (or all updates if you don't set OnMessage) bot.OnError += ... to handle errors/exceptions during polling or your handlers Note: Second argument to OnMessage event specifies which kind of update it was ( edited , channel or business message?) When you assign those events, polling starts automatically, you don't have anything to do. Polling will stop when you remove (-=) your events, or when you cancel the global cancellation token You can also use await bot.DropPendingUpdatesAsync() before setting those events to ignore past updates. The Console example project has been updated to demonstrate these events.","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Simplified polling with events (v21.7)","id":"187","title":"Simplified polling with events (v21.7)"},"188":{"body":"If Telegram servers fail on your API call with this error and ask you to to retry in less than 60 seconds, TelegramBotClient will now automatically wait for the requested delay and retry sending the same request up to 3 times. This is configurable using Options on the constructor: using var cts = new CancellationTokenSource();\nvar options = new TelegramBotClientOptions(token) { RetryThreshold = 120, RetryCount = 2 };\nvar bot = new TelegramBotClient(options, cancellationToken: cts.Token); *️⃣ This is a change of behavior compared to previous versions, but probably a welcome one. To disable this system and keep the same behavior as previous versions, use RetryThreshold = 0 Notes for advanced users: If this happens while uploading files (InputFile streams), the streams will be reset to their start position in order to be sent again If your streams are non-seekable (no problem with MemoryStream/FileStream) , the full HTTP request to Bot API will be buffered before the first sending (so it can lead to a temporary use of memory if you're sending big files)","breadcrumbs":"Migration guides to newer versions » Migrate to v21.* » Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)","id":"188","title":"Automatic retrying API calls in case of \"Too Many Requests\" (v21.9)"},"189":{"body":"","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Migration guide for version 19.0","id":"189","title":"Migration guide for version 19.0"},"19":{"body":"Multimedia messages can optionally have a caption attached to them. Here we sent a caption in HTML format. A user can click on Pixabay in the caption to open its URL in the browser. Similar to message entities discussed before, caption entities on Message object are the result of parsing formatted(Markdown or HTML) caption text. Try inspecting these properties in debug mode: message.Caption: caption in plain text without formatting message.CaptionEntities: info about special entities in the caption message.CaptionEntityValues: text values of mentioned entities","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Caption","id":"19","title":"Caption"},"190":{"body":"New topics functionality allow bots interact with users in topic specified by messageThreadId parameter. We try to keep our Bot API implementation as close to Telegram Bot API as possible. This means, that the new messageThreadId now the first optional parameter for a variety of methods. Consider to use named parameters to avoid confusion with changed parameter order. -Message message = await bot.SendTextMessageAsync(\n- _fixture.SupergroupChat.Id,\n- \"Please click on *Notify* button.\",\n- cancellationToken);\n+Message message = await bot.SendTextMessageAsync(\n+ chatId: _fixture.SupergroupChat.Id,\n+ text: \"Please click on *Notify* button.\",\n+ messageThreadId: threadId,\n+ cancellationToken: cancellationToken);","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Topics in Groups","id":"190","title":"Topics in Groups"},"191":{"body":"Old InputMedia* class hierarchy poorly reflected actual file-related APIs. We removed old hierarchy of InputFile related classes such as InputOnlineFile, InputTelegramFile, InputFileStream, etc., and also removed all implicit casts to them. From now on you should explicitly specify one of file types: InputFileStream for Stream content, InputFileUrl for URL and InputFileId if you want to use existing file_id. For convenience the base InputType class has factory methods to create the correct types: InputFile.FromStream(Stream stream, string? fileName = default) for streams InputFile.FromString(string urlOrFileId) for URLs or file ids InputFile.FromUri(Uri url) - for URLs as strings InputFile.FromUri(string url) - for URLs as URIs InputFile.FromFileId(string fileId) - for file ids The migration scheme looks like that: Previous method New method new InputTelegramType(string) InputFile.FromId(string), InputFile.FromString(string) new InputTelegramType(Stream, string?) InputFile.FromStream(Stream, string?) new InputFileStream(Stream) InputFile.FromStream(Stream) new InputOnlineFile(string) InputFile.FromId(string), InputFile.FromString(string), InputFile.FromString(string), InputFile.FromUrl(string), InputFile.FromUrl(Uri) new InputOnlineFile(Stream, string?) InputFile.FromStream(Stream, string?) raw Stream InputFile.FromStream(Stream) raw string InputFile.FromString(string) raw URI InputFile.FromUrl(URI)","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » New InputFile Hierarchy","id":"191","title":"New InputFile Hierarchy"},"192":{"body":"Implicit conversion from ChatId to string was removed due to complaints and problems it caused. The migration path is to explicitly call ChatId.ToString() method.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » ChatId implicit conversion","id":"192","title":"ChatId implicit conversion"},"193":{"body":"All methods and types with animated, static and video sticker distinction were removed and replaced with a single set of sticker related methods per new Bot API updates: AddAnimatedStickerToSetAsync, AddStaticStickerToSetAsync, AddVideoStickerToSetAsync, etc. Remove the words Static, Animated and Video from sticker related methods in your code Associated emojies and masks were moved to a separate type InputSticker, use them there instead, consult the official Bot API docs for a more detailed information","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Stickers","id":"193","title":"Stickers"},"194":{"body":"Since .NET Core 3.1 LTS status is not officialy supported anymore we changed the target to netstandard2.0 and net6.0 instead. If you're using .NET Core 3.1 or .NET 5 runtimes you need to use the build for netstandard2.0 instead. If you relied on IAsyncEnumerable implementation of poller you need to move to .NET 6 instead.","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » .NET Core 3.1 removed as a separate target framework","id":"194","title":".NET Core 3.1 removed as a separate target framework"},"195":{"body":"Message.Type returns MessageType.Animation when the message contains an Animation, use MessageType.Animation instead of MessageType.Document to check if the message contains an animation Property CanSendMediaMessages was removed from the types ChatMemberRestricted and ChatPermissions and replaced with more granular permissions, use them instead Removed method GetChatMembersCountAsync, use GetChatMemberCountAsync Removed method KickChatMemberAsync, use BanChatMemberAsync Properties and types VoiceChatEnded, VoiceChatParticipantsInvited, VoiceChatScheduled, VoiceChatStarted removed, use methods and types which start with Video* instead All propties with the word Thumb in them were renamed to contain the word Thumbnail per new Bot API updates A new type InlineQueryResultsButton is used instead of SwitchPmText and SwitchPmParameter properties, consult the official Bot API docs","breadcrumbs":"Migration guides to newer versions » Migrate to v19.* » Other changes","id":"195","title":"Other changes"},"196":{"body":"Most breaking changes in v18 come from new Bot API changes, such as: In Bot API 6.0 voice_chat* related message properties were deprecated in favour of video_chat* with the same semantics and shape. With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. So static .WEBP *StickerSet* methods and requests were given a Static prefix. Removed untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class. As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long?. A new way of configuring the client. ApiRequestEventArgs contains full request data. Complete list of changes is available in CHANGELOG","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » Migration guide for version 18.0","id":"196","title":"Migration guide for version 18.0"},"197":{"body":"Telegram renamed voice_chat_* properties in the Message class and with video_chat_* onces so we replaced corresponding MessageType enum members with the new ones. Following properties in Message class and corresponding enum members in MessageType enum were changed: -VoiceChatScheduled\n-VoiceChatStarted\n-VoiceChatEnded\n-VoiceChatParticipantsInvited\n+VideoChatScheduled\n+VideoChatStarted\n+VideoChatEnded\n+VideoChatParticipantsInvited Also property CanManageVoiceChats in ChatMemberAdministrator and PromoteChatMemberRequest classes was renamed to CanManageVideoChats.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 1. Removal of VoiceChat* properties in Message object","id":"197","title":"1. Removal of VoiceChat* properties in Message object"},"198":{"body":"With introduction of video stickers in Bot API 5.7 we needed a way to separate methods for different sticker types. We already used Animated and Video suffix for methods related to animated and video stickers so we decided to do the same for the static stickers: Classes CreateNewStickerSetRequest and AddStickerToSetRequest were renamed to CreateNewStaticStickerSetRequest and AddStaticStickerToSetRequest. Methods CreateNewStickerSetAsync and AddStickerToSetAsync where renamed to CreateStaticNewStickerSetAsync and AddStaticStickerToSetAsync.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 2. Renaming static sticker methods and classes","id":"198","title":"2. Renaming static sticker methods and classes"},"199":{"body":"The untilDate parameter from TelegramBotClientExtensions.BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class were removed from the Bot API.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class","id":"199","title":"3. Removal of untilDate parameter from BanChatSenderChatAsync method and UntilDate property from BanChatSenderChatRequest class"},"2":{"body":"This book is filled with ready-to-use snippets of code, but you can also find full project examples at our Telegram.Bot.Examples Github repository, featuring: Simple Console apps (long polling) Webhook ASP.NET example (with Controllers or Minimal APIs) Full-featured advanced solution Serverless Functions implementations","breadcrumbs":"Introduction » 🪄 More examples","id":"2","title":"🪄 More examples"},"20":{"body":"The message returned from this method represents a photo message because message.Photo has a value. Its value is a PhotoSize array with each element representing the same photo in different dimensions. If your bot needs to send this photo again at some point, it is recommended to store this array so you can reuse the file_id value. Here is how message.Photo array looks like in JSON: [ { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABCQawlb-dBXqBZUEAAEC\", \"file_size\": 1254, \"width\": 90, \"height\": 60 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABAKByRnc22RmBpUEAAEC\", \"file_size\": 16419, \"width\": 320, \"height\": 213 }, { \"file_id\": \"AgADBAADDqgxG-QDDVCm5JVvld7MN0z6kBkABHezqGiNOz9yB5UEAAEC\", \"file_size\": 57865, \"width\": 640, \"height\": 426 }\n]","breadcrumbs":"Beginner » Sending Messages » Photo & Sticker » Photo Message","id":"20","title":"Photo Message"},"200":{"body":"As of the next update some users will be able to upload up to 4GB files, so we changed FileBase.FileSize type to long? to accommodate this change.","breadcrumbs":"Migration guides to newer versions » Migrate to v18.* » 4. Lifting of the FileSize limit","id":"200","title":"4. Lifting of the FileSize limit"},"201":{"body":"Starting with this release client configuration parameters should be passed through TelegramBotClientOptions class. You need to create an instance of TelegramBotClientOptions and pass it to the client: using Telegram.Bot; var options = new TelegramBotClientOptions( token: \"