Skip to main content

rustigram_types/
message.rs

1use serde::{Deserialize, Serialize};
2
3use crate::chat::{Chat, Location, Venue};
4use crate::checklist::{Checklist, ChecklistTasksAdded, ChecklistTasksDone};
5use crate::direct_messages::{
6    DirectMessagePriceChanged, DirectMessagesTopic, PaidMessagePriceChanged,
7};
8use crate::file::{Animation, Audio, Document, LivePhoto, PhotoSize, Video, VideoNote, Voice};
9use crate::keyboard::InlineKeyboardMarkup;
10use crate::managed_bot::ManagedBotCreated;
11use crate::poll::{Poll, PollOptionAdded, PollOptionDeleted};
12use crate::sticker::Sticker;
13use crate::suggested_post::{
14    SuggestedPostApprovalFailed, SuggestedPostApproved, SuggestedPostDeclined, SuggestedPostInfo,
15    SuggestedPostPaid, SuggestedPostRefunded,
16};
17use crate::user::User;
18
19/// A Telegram message.
20///
21/// Only fields that were actually sent will be `Some`. Consult the
22/// official Bot API documentation for field availability rules.
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct Message {
25    /// Unique message identifier inside this chat.
26    pub message_id: i64,
27
28    /// Optional — unique identifier of a message thread to which the message belongs.
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub message_thread_id: Option<i64>,
31
32    /// Information about the direct messages chat topic that contains the message.
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub direct_messages_topic: Option<DirectMessagesTopic>,
35
36    /// Sender of the message; empty for messages sent to channels.
37    #[serde(skip_serializing_if = "Option::is_none")]
38    pub from: Option<User>,
39
40    /// Sender of the message; empty for messages sent to channels or on behalf of a chat.
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub sender_chat: Option<Chat>,
43
44    /// For supergroup messages — boost count of the sender.
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub sender_boost_count: Option<u32>,
47
48    /// The bot that actually sent the message on behalf of the business account.
49    #[serde(skip_serializing_if = "Option::is_none")]
50    pub sender_business_bot: Option<User>,
51
52    /// Tag or custom title of the sender; for supergroups only (Bot API 9.5).
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub sender_tag: Option<String>,
55
56    /// Date the message was sent, as a Unix timestamp.
57    pub date: i64,
58
59    /// Unique identifier of the business connection from which the message was received.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub business_connection_id: Option<String>,
62
63    /// Conversation the message belongs to.
64    pub chat: Chat,
65
66    /// Information about the original message for forwarded messages.
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub forward_origin: Option<MessageOrigin>,
69
70    /// `true` if the message is sent to a forum topic.
71    #[serde(skip_serializing_if = "Option::is_none")]
72    pub is_topic_message: Option<bool>,
73
74    /// `true` if the message is a channel post automatically forwarded to the
75    /// connected discussion group.
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub is_automatic_forward: Option<bool>,
78
79    /// For replies in the same chat and message thread, the original message.
80    #[serde(skip_serializing_if = "Option::is_none")]
81    pub reply_to_message: Option<Box<Message>>,
82
83    /// Information about the message that is being replied to from another chat or topic.
84    #[serde(skip_serializing_if = "Option::is_none")]
85    pub external_reply: Option<ExternalReplyInfo>,
86
87    /// For replies that quote part of the original message, the quoted part.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub quote: Option<TextQuote>,
90
91    /// For replies to a story, the original story.
92    #[serde(skip_serializing_if = "Option::is_none")]
93    pub reply_to_story: Option<serde_json::Value>,
94
95    /// Identifier of the checklist task being replied to.
96    #[serde(skip_serializing_if = "Option::is_none")]
97    pub reply_to_checklist_task_id: Option<i64>,
98
99    /// Persistent identifier of the poll option being replied to.
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub reply_to_poll_option_id: Option<String>,
102
103    /// Bot through which the message was sent.
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub via_bot: Option<User>,
106
107    /// Date the message was last edited, as a Unix timestamp.
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub edit_date: Option<i64>,
110
111    /// `true` if the message can't be forwarded.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub has_protected_content: Option<bool>,
114
115    /// `true` if the message was sent by an implicit action.
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub is_from_offline: Option<bool>,
118
119    /// `true` if the message is a paid post.
120    ///
121    /// Paid posts must not be deleted for 24 hours after sending and cannot be edited.
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub is_paid_post: Option<bool>,
124
125    /// The unique identifier of a media message group this message belongs to.
126    #[serde(skip_serializing_if = "Option::is_none")]
127    pub media_group_id: Option<String>,
128
129    /// Signature of the post author for messages in channels.
130    #[serde(skip_serializing_if = "Option::is_none")]
131    pub author_signature: Option<String>,
132
133    /// Number of Telegram Stars paid by the sender to send this message.
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub paid_star_count: Option<i64>,
136
137    /// Actual UTF-8 text of the message (0–4096 characters).
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub text: Option<String>,
140
141    /// Special entities like usernames, URLs, bot commands, etc.
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub entities: Option<Vec<MessageEntity>>,
144
145    /// Options used for link preview generation.
146    #[serde(skip_serializing_if = "Option::is_none")]
147    pub link_preview_options: Option<LinkPreviewOptions>,
148
149    /// Information about a suggested post; present when the message is a suggested
150    /// post in a channel direct messages chat.
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub suggested_post_info: Option<SuggestedPostInfo>,
153
154    /// Unique identifier of the message effect added to the message.
155    #[serde(skip_serializing_if = "Option::is_none")]
156    pub effect_id: Option<String>,
157
158    // Media fields
159    /// Animation attached to the message.
160    #[serde(skip_serializing_if = "Option::is_none")]
161    pub animation: Option<Animation>,
162    /// Audio file attached to the message.
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub audio: Option<Audio>,
165    /// Document attached to the message.
166    #[serde(skip_serializing_if = "Option::is_none")]
167    pub document: Option<Document>,
168    /// Paid media attached to the message.
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub paid_media: Option<serde_json::Value>,
171    /// Photo attached to the message (array of sizes).
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub photo: Option<Vec<PhotoSize>>,
174    /// Live photo attached to the message.
175    #[serde(skip_serializing_if = "Option::is_none")]
176    pub live_photo: Option<LivePhoto>,
177    /// Sticker attached to the message.
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub sticker: Option<Sticker>,
180    /// Story attached to the message.
181    #[serde(skip_serializing_if = "Option::is_none")]
182    pub story: Option<serde_json::Value>,
183    /// Video attached to the message.
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub video: Option<Video>,
186    /// Video note attached to the message.
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub video_note: Option<VideoNote>,
189    /// Voice note attached to the message.
190    #[serde(skip_serializing_if = "Option::is_none")]
191    pub voice: Option<Voice>,
192
193    /// Caption for the animation, audio, document, paid media, photo, video or voice.
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub caption: Option<String>,
196
197    /// Special entities in the caption.
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub caption_entities: Option<Vec<MessageEntity>>,
200
201    /// `true` if the caption must be shown above the message media.
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub show_caption_above_media: Option<bool>,
204
205    /// `true` if the message media is covered by a spoiler animation.
206    #[serde(skip_serializing_if = "Option::is_none")]
207    pub has_media_spoiler: Option<bool>,
208
209    /// Checklist attached to the message.
210    #[serde(skip_serializing_if = "Option::is_none")]
211    pub checklist: Option<Checklist>,
212
213    // Service message types
214    /// Contact shared in the message.
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub contact: Option<Contact>,
217    /// Dice result in the message.
218    #[serde(skip_serializing_if = "Option::is_none")]
219    pub dice: Option<Dice>,
220    /// Game in the message.
221    #[serde(skip_serializing_if = "Option::is_none")]
222    pub game: Option<serde_json::Value>,
223    /// Poll in the message.
224    #[serde(skip_serializing_if = "Option::is_none")]
225    pub poll: Option<Poll>,
226    /// Venue in the message.
227    #[serde(skip_serializing_if = "Option::is_none")]
228    pub venue: Option<Venue>,
229    /// Location in the message.
230    #[serde(skip_serializing_if = "Option::is_none")]
231    pub location: Option<Location>,
232
233    // Group events
234    /// New members that joined the group.
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub new_chat_members: Option<Vec<User>>,
237    /// A member that left the group.
238    #[serde(skip_serializing_if = "Option::is_none")]
239    pub left_chat_member: Option<User>,
240    /// Service message: chat owner has left.
241    #[serde(skip_serializing_if = "Option::is_none")]
242    pub chat_owner_left: Option<ChatOwnerLeft>,
243    /// Service message: chat owner has changed.
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub chat_owner_changed: Option<ChatOwnerChanged>,
246    /// New chat title (service message).
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub new_chat_title: Option<String>,
249    /// New chat photo (service message).
250    #[serde(skip_serializing_if = "Option::is_none")]
251    pub new_chat_photo: Option<Vec<PhotoSize>>,
252    /// `true` if the chat photo was deleted (service message).
253    #[serde(skip_serializing_if = "Option::is_none")]
254    pub delete_chat_photo: Option<bool>,
255    /// `true` if the group was created (service message).
256    #[serde(skip_serializing_if = "Option::is_none")]
257    pub group_chat_created: Option<bool>,
258    /// `true` if the supergroup was created (service message).
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub supergroup_chat_created: Option<bool>,
261    /// `true` if the channel was created (service message).
262    #[serde(skip_serializing_if = "Option::is_none")]
263    pub channel_chat_created: Option<bool>,
264    /// Auto-delete timer changed (service message).
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub message_auto_delete_timer_changed: Option<serde_json::Value>,
267    /// The group has been migrated to a supergroup with this ID.
268    #[serde(skip_serializing_if = "Option::is_none")]
269    pub migrate_to_chat_id: Option<i64>,
270    /// The supergroup has been migrated from a group with this ID.
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub migrate_from_chat_id: Option<i64>,
273    /// The pinned message (service message).
274    #[serde(skip_serializing_if = "Option::is_none")]
275    pub pinned_message: Option<Box<Message>>,
276
277    /// Inline keyboard attached to the message.
278    #[serde(skip_serializing_if = "Option::is_none")]
279    pub reply_markup: Option<InlineKeyboardMarkup>,
280
281    // Payment fields
282    /// Invoice for a payment (service message).
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub invoice: Option<serde_json::Value>,
285    /// Successful payment information (service message).
286    #[serde(skip_serializing_if = "Option::is_none")]
287    pub successful_payment: Option<serde_json::Value>,
288    /// Refunded payment information (service message).
289    #[serde(skip_serializing_if = "Option::is_none")]
290    pub refunded_payment: Option<serde_json::Value>,
291
292    // Web app
293    /// Data from the Web App.
294    #[serde(skip_serializing_if = "Option::is_none")]
295    pub web_app_data: Option<WebAppData>,
296
297    // Forum topic events
298    /// Forum topic created (service message).
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub forum_topic_created: Option<serde_json::Value>,
301    /// Forum topic edited (service message).
302    #[serde(skip_serializing_if = "Option::is_none")]
303    pub forum_topic_edited: Option<serde_json::Value>,
304    /// Forum topic closed (service message).
305    #[serde(skip_serializing_if = "Option::is_none")]
306    pub forum_topic_closed: Option<serde_json::Value>,
307    /// Forum topic reopened (service message).
308    #[serde(skip_serializing_if = "Option::is_none")]
309    pub forum_topic_reopened: Option<serde_json::Value>,
310    /// General forum topic hidden (service message).
311    #[serde(skip_serializing_if = "Option::is_none")]
312    pub general_forum_topic_hidden: Option<serde_json::Value>,
313    /// General forum topic unhidden (service message).
314    #[serde(skip_serializing_if = "Option::is_none")]
315    pub general_forum_topic_unhidden: Option<serde_json::Value>,
316
317    // Managed bot events
318    /// Service message: a new managed bot was created (Bot API 9.6).
319    #[serde(skip_serializing_if = "Option::is_none")]
320    pub managed_bot_created: Option<ManagedBotCreated>,
321
322    // Poll events
323    /// Service message: an option was added to a poll (Bot API 9.6).
324    #[serde(skip_serializing_if = "Option::is_none")]
325    pub poll_option_added: Option<PollOptionAdded>,
326    /// Service message: an option was deleted from a poll (Bot API 9.6).
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub poll_option_deleted: Option<PollOptionDeleted>,
329
330    // Checklist events
331    /// Service message: tasks in a checklist were marked done or not done.
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub checklist_tasks_done: Option<ChecklistTasksDone>,
334    /// Service message: tasks were added to a checklist.
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub checklist_tasks_added: Option<ChecklistTasksAdded>,
337
338    // Direct messages events
339    /// Service message: the price for paid messages in the direct messages chat changed.
340    #[serde(skip_serializing_if = "Option::is_none")]
341    pub direct_message_price_changed: Option<DirectMessagePriceChanged>,
342    /// Service message: the price for paid messages in the chat changed.
343    #[serde(skip_serializing_if = "Option::is_none")]
344    pub paid_message_price_changed: Option<PaidMessagePriceChanged>,
345
346    // Suggested post events
347    /// Service message: a suggested post was approved.
348    #[serde(skip_serializing_if = "Option::is_none")]
349    pub suggested_post_approved: Option<SuggestedPostApproved>,
350    /// Service message: approval of a suggested post has failed.
351    #[serde(skip_serializing_if = "Option::is_none")]
352    pub suggested_post_approval_failed: Option<SuggestedPostApprovalFailed>,
353    /// Service message: a suggested post was declined.
354    #[serde(skip_serializing_if = "Option::is_none")]
355    pub suggested_post_declined: Option<SuggestedPostDeclined>,
356    /// Service message: payment for a suggested post was received.
357    #[serde(skip_serializing_if = "Option::is_none")]
358    pub suggested_post_paid: Option<SuggestedPostPaid>,
359    /// Service message: payment for a suggested post was refunded.
360    #[serde(skip_serializing_if = "Option::is_none")]
361    pub suggested_post_refunded: Option<SuggestedPostRefunded>,
362
363    // Guest mode fields
364    /// For a message sent by a guest bot, the user whose original message triggered the bot's response.
365    #[serde(skip_serializing_if = "Option::is_none")]
366    pub guest_bot_caller_user: Option<User>,
367
368    /// For a message sent by a guest bot, the chat whose original message triggered the bot's response.
369    #[serde(skip_serializing_if = "Option::is_none")]
370    pub guest_bot_caller_chat: Option<crate::chat::Chat>,
371
372    /// The unique identifier for the guest query.
373    ///
374    /// Use with [`answerGuestQuery`](https://core.telegram.org/bots/api#answerguestquery) to send a
375    /// response. If non-empty, the message belongs to a chat of the corresponding business account
376    /// independent from any potential bot chat sharing the same identifier.
377    #[serde(skip_serializing_if = "Option::is_none")]
378    pub guest_query_id: Option<String>,
379}
380
381impl Message {
382    /// Returns the effective text of the message — `text` or `caption`.
383    #[must_use]
384    pub fn effective_text(&self) -> Option<&str> {
385        self.text.as_deref().or(self.caption.as_deref())
386    }
387
388    /// Returns `true` if the message is a command (text starts with `/`).
389    #[must_use]
390    pub fn is_command(&self) -> bool {
391        self.entities
392            .as_deref()
393            .unwrap_or_default()
394            .iter()
395            .any(|e| e.kind == MessageEntityKind::BotCommand && e.offset == 0)
396    }
397
398    /// Extracts the command string (e.g. `"start"` from `/start@bot`), if present.
399    #[must_use]
400    pub fn command(&self) -> Option<&str> {
401        let text = self.text.as_deref()?;
402        let entity = self
403            .entities
404            .as_deref()?
405            .iter()
406            .find(|e| e.kind == MessageEntityKind::BotCommand && e.offset == 0)?;
407        let raw = &text[..entity.length as usize];
408        // Strip the `@BotUsername` suffix if present.
409        Some(
410            raw.find('@')
411                .map_or(raw, |i| &raw[..i])
412                .trim_start_matches('/'),
413        )
414    }
415}
416
417/// Type of a message entity.
418#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
419#[serde(rename_all = "snake_case")]
420pub enum MessageEntityKind {
421    /// @username mention.
422    Mention,
423    /// #hashtag.
424    Hashtag,
425    /// $cashtag.
426    Cashtag,
427    /// /bot_command.
428    BotCommand,
429    /// Plain URL.
430    Url,
431    /// Email address.
432    Email,
433    /// Phone number.
434    PhoneNumber,
435    /// **Bold** text.
436    Bold,
437    /// _Italic_ text.
438    Italic,
439    /// Underlined text.
440    Underline,
441    /// ~~Strikethrough~~ text.
442    Strikethrough,
443    /// ||Spoiler|| text.
444    Spoiler,
445    /// Block quotation.
446    Blockquote,
447    /// An "expandable" block quotation that can be expanded to show the full text.
448    ExpandableBlockquote,
449    /// Monospaced text.
450    Code,
451    /// Monospaced block.
452    Pre,
453    /// A text link. The `url` field will contain the destination URL.
454    TextLink,
455    /// A text mention of a user. The `user` field will contain the mentioned user.
456    TextMention,
457    /// Custom emoji. The `custom_emoji_id` field will contain the identifier of the custom emoji.
458    CustomEmoji,
459    /// Date/time entity.
460    DateTime,
461}
462
463/// One special entity in a message text.
464#[derive(Debug, Clone, Serialize, Deserialize)]
465pub struct MessageEntity {
466    /// Type of the entity.
467    #[serde(rename = "type")]
468    pub kind: MessageEntityKind,
469    /// Offset in UTF-16 code units to the start of the entity.
470    pub offset: u32,
471    /// Length of the entity in UTF-16 code units.
472    pub length: u32,
473    /// For `TextLink` — URL.
474    #[serde(skip_serializing_if = "Option::is_none")]
475    pub url: Option<String>,
476    /// For `TextMention` — the mentioned user.
477    #[serde(skip_serializing_if = "Option::is_none")]
478    pub user: Option<User>,
479    /// For `Pre` — the programming language.
480    #[serde(skip_serializing_if = "Option::is_none")]
481    pub language: Option<String>,
482    /// For `CustomEmoji` — identifier of the custom emoji.
483    #[serde(skip_serializing_if = "Option::is_none")]
484    pub custom_emoji_id: Option<String>,
485    /// For `DateTime` — Unix timestamp associated with the entity.
486    #[serde(skip_serializing_if = "Option::is_none")]
487    pub unix_time: Option<i64>,
488    /// For `DateTime` — format string (`r|w?[dD]?[tT]?`).
489    #[serde(skip_serializing_if = "Option::is_none")]
490    pub date_time_format: Option<String>,
491}
492
493/// Origin of a forwarded message.
494#[derive(Debug, Clone, Serialize, Deserialize)]
495#[serde(tag = "type", rename_all = "snake_case")]
496pub enum MessageOrigin {
497    /// Forwarded from a user with a visible profile.
498    User {
499        /// Date the original message was sent, as a Unix timestamp.
500        date: i64,
501        /// The user who sent the original message.
502        sender_user: User,
503    },
504    /// Forwarded from a user with a hidden profile.
505    HiddenUser {
506        /// Date the original message was sent, as a Unix timestamp.
507        date: i64,
508        /// Name of the user who sent the original message.
509        sender_user_name: String,
510    },
511    /// Forwarded from a chat on behalf of the chat itself.
512    Chat {
513        /// Date the original message was sent, as a Unix timestamp.
514        date: i64,
515        /// The chat that sent the original message.
516        sender_chat: Chat,
517        /// Signature of the original post author.
518        #[serde(skip_serializing_if = "Option::is_none")]
519        author_signature: Option<String>,
520    },
521    /// Forwarded from a channel.
522    Channel {
523        /// Date the original message was sent, as a Unix timestamp.
524        date: i64,
525        /// The channel that sent the original message.
526        chat: Chat,
527        /// Identifier of the original message in the channel.
528        message_id: i64,
529        /// Signature of the original post author.
530        #[serde(skip_serializing_if = "Option::is_none")]
531        author_signature: Option<String>,
532    },
533}
534
535/// Parameters for replying to a message.
536#[derive(Debug, Clone, Serialize, Deserialize)]
537pub struct ReplyParameters {
538    /// Identifier of the message that will be replied to.
539    pub message_id: i64,
540    /// Chat containing the message.
541    #[serde(skip_serializing_if = "Option::is_none")]
542    pub chat_id: Option<crate::user::ChatId>,
543    /// `true` if the message should be sent even if the specified message is not found.
544    #[serde(skip_serializing_if = "Option::is_none")]
545    pub allow_sending_without_reply: Option<bool>,
546    /// Quoted part of the message to be replied to.
547    #[serde(skip_serializing_if = "Option::is_none")]
548    pub quote: Option<String>,
549    /// Parse mode for the quote.
550    #[serde(skip_serializing_if = "Option::is_none")]
551    pub quote_parse_mode: Option<ParseMode>,
552    /// Special entities in the quote.
553    #[serde(skip_serializing_if = "Option::is_none")]
554    pub quote_entities: Option<Vec<MessageEntity>>,
555    /// Position of the quote in the original message (UTF-16 offset).
556    #[serde(skip_serializing_if = "Option::is_none")]
557    pub quote_position: Option<u32>,
558    /// Identifier of the poll option being replied to.
559    #[serde(skip_serializing_if = "Option::is_none")]
560    pub poll_option_id: Option<String>,
561    /// Identifier of the checklist task being replied to.
562    #[serde(skip_serializing_if = "Option::is_none")]
563    pub checklist_task_id: Option<i64>,
564}
565
566/// Text parse mode for message formatting.
567#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
568pub enum ParseMode {
569    /// Markdown v2 — recommended.
570    MarkdownV2,
571    /// HTML formatting.
572    HTML,
573    /// Legacy Markdown — limited.
574    Markdown,
575}
576
577/// Reaction type on a message.
578#[derive(Debug, Clone, Serialize, Deserialize)]
579#[serde(tag = "type", rename_all = "snake_case")]
580pub enum ReactionType {
581    /// A standard emoji reaction.
582    Emoji {
583        /// The emoji character.
584        emoji: String,
585    },
586    /// A custom emoji reaction.
587    CustomEmoji {
588        /// Identifier of the custom emoji.
589        custom_emoji_id: String,
590    },
591    /// A paid star reaction.
592    Paid,
593}
594
595/// Options for controlling how links are previewed in messages.
596#[derive(Debug, Clone, Default, Serialize, Deserialize)]
597pub struct LinkPreviewOptions {
598    /// `true` if link preview is disabled.
599    #[serde(skip_serializing_if = "Option::is_none")]
600    pub is_disabled: Option<bool>,
601    /// URL to use for the link preview.
602    #[serde(skip_serializing_if = "Option::is_none")]
603    pub url: Option<String>,
604    /// `true` if the media in the link preview should be shrunk.
605    #[serde(skip_serializing_if = "Option::is_none")]
606    pub prefer_small_media: Option<bool>,
607    /// `true` if the media in the link preview should be enlarged.
608    #[serde(skip_serializing_if = "Option::is_none")]
609    pub prefer_large_media: Option<bool>,
610    /// `true` if the link preview should be shown above the message text.
611    #[serde(skip_serializing_if = "Option::is_none")]
612    pub show_above_text: Option<bool>,
613}
614
615/// Information about the quoted part of a message that is replied to.
616#[derive(Debug, Clone, Serialize, Deserialize)]
617pub struct TextQuote {
618    /// Text of the quoted part of the message.
619    pub text: String,
620    /// Special entities in the quote.
621    #[serde(skip_serializing_if = "Option::is_none")]
622    pub entities: Option<Vec<MessageEntity>>,
623    /// Approximate quote position in the original message (UTF-16 offset).
624    pub position: u32,
625    /// `true` if the quote was chosen manually by the message sender.
626    #[serde(skip_serializing_if = "Option::is_none")]
627    pub is_manual: Option<bool>,
628}
629
630/// Information about a message that is being replied to from outside the thread.
631#[derive(Debug, Clone, Serialize, Deserialize)]
632pub struct ExternalReplyInfo {
633    /// Origin of the message being replied to.
634    pub origin: MessageOrigin,
635    /// Chat the original message belongs to (if not the current chat).
636    #[serde(skip_serializing_if = "Option::is_none")]
637    pub chat: Option<Chat>,
638    /// Identifier of the original message in the original chat.
639    #[serde(skip_serializing_if = "Option::is_none")]
640    pub message_id: Option<i64>,
641    /// Options for link preview.
642    #[serde(skip_serializing_if = "Option::is_none")]
643    pub link_preview_options: Option<LinkPreviewOptions>,
644    /// Animation in the original message.
645    #[serde(skip_serializing_if = "Option::is_none")]
646    pub animation: Option<Animation>,
647    /// Audio in the original message.
648    #[serde(skip_serializing_if = "Option::is_none")]
649    pub audio: Option<Audio>,
650    /// Document in the original message.
651    #[serde(skip_serializing_if = "Option::is_none")]
652    pub document: Option<Document>,
653    /// Photo in the original message.
654    #[serde(skip_serializing_if = "Option::is_none")]
655    pub photo: Option<Vec<PhotoSize>>,
656    /// Live photo in the original message.
657    #[serde(skip_serializing_if = "Option::is_none")]
658    pub live_photo: Option<LivePhoto>,
659    /// Sticker in the original message.
660    #[serde(skip_serializing_if = "Option::is_none")]
661    pub sticker: Option<Sticker>,
662    /// Video in the original message.
663    #[serde(skip_serializing_if = "Option::is_none")]
664    pub video: Option<Video>,
665    /// Video note in the original message.
666    #[serde(skip_serializing_if = "Option::is_none")]
667    pub video_note: Option<VideoNote>,
668    /// Voice note in the original message.
669    #[serde(skip_serializing_if = "Option::is_none")]
670    pub voice: Option<Voice>,
671    /// `true` if the media is covered by a spoiler animation.
672    #[serde(skip_serializing_if = "Option::is_none")]
673    pub has_media_spoiler: Option<bool>,
674    /// Checklist in the original message.
675    #[serde(skip_serializing_if = "Option::is_none")]
676    pub checklist: Option<Checklist>,
677    /// Contact in the original message.
678    #[serde(skip_serializing_if = "Option::is_none")]
679    pub contact: Option<Contact>,
680    /// Dice in the original message.
681    #[serde(skip_serializing_if = "Option::is_none")]
682    pub dice: Option<Dice>,
683    /// Location in the original message.
684    #[serde(skip_serializing_if = "Option::is_none")]
685    pub location: Option<Location>,
686    /// Venue in the original message.
687    #[serde(skip_serializing_if = "Option::is_none")]
688    pub venue: Option<Venue>,
689    /// Poll in the original message.
690    #[serde(skip_serializing_if = "Option::is_none")]
691    pub poll: Option<Poll>,
692}
693
694/// Phone contact.
695#[derive(Debug, Clone, Serialize, Deserialize)]
696pub struct Contact {
697    /// Contact's phone number.
698    pub phone_number: String,
699    /// Contact's first name.
700    pub first_name: String,
701    /// Contact's last name.
702    #[serde(skip_serializing_if = "Option::is_none")]
703    pub last_name: Option<String>,
704    /// Contact's Telegram user ID.
705    #[serde(skip_serializing_if = "Option::is_none")]
706    pub user_id: Option<i64>,
707    /// Contact's vCard.
708    #[serde(skip_serializing_if = "Option::is_none")]
709    pub vcard: Option<String>,
710}
711
712/// Animated dice with a random value.
713#[derive(Debug, Clone, Serialize, Deserialize)]
714pub struct Dice {
715    /// Emoji on which the dice throw animation is based.
716    pub emoji: String,
717    /// Value of the dice (1–6 for 🎲🎯🎳; 1–5 for 🏀⚽; 1–64 for 🎰).
718    pub value: u8,
719}
720
721/// Data sent from a Web App.
722#[derive(Debug, Clone, Serialize, Deserialize)]
723pub struct WebAppData {
724    /// Data sent by the Web App.
725    pub data: String,
726    /// Text of the button that opened the Web App.
727    pub button_text: String,
728}
729
730/// Information about a Web App.
731#[derive(Debug, Clone, Serialize, Deserialize)]
732pub struct WebAppInfo {
733    /// HTTPS URL of the Web App.
734    pub url: String,
735}
736
737/// Lightweight message identifier returned by `copyMessage`.
738#[derive(Debug, Clone, Serialize, Deserialize)]
739pub struct MessageId {
740    /// Identifier of the message.
741    pub message_id: i64,
742}
743
744/// Service message: the chat owner left the chat (Bot API 9.4).
745#[derive(Debug, Clone, Serialize, Deserialize)]
746pub struct ChatOwnerLeft {
747    /// The user who will become the new owner if the previous owner does not return.
748    #[serde(skip_serializing_if = "Option::is_none")]
749    pub new_owner: Option<User>,
750}
751
752/// Service message: ownership of the chat changed (Bot API 9.4).
753#[derive(Debug, Clone, Serialize, Deserialize)]
754pub struct ChatOwnerChanged {
755    /// The new owner of the chat.
756    pub new_owner: User,
757}