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