Skip to main content

rustigram_api/
client.rs

1use std::sync::Arc;
2use std::time::Duration;
3
4use reqwest::multipart::{Form, Part};
5use serde::de::DeserializeOwned;
6use serde::Serialize;
7use tracing::{debug, warn};
8
9use crate::error::{Error, Result};
10use crate::methods::bot_settings::*;
11use crate::methods::business::*;
12use crate::methods::chat_management::*;
13use crate::methods::editing::*;
14use crate::methods::forum::*;
15use crate::methods::games::*;
16use crate::methods::getters::*;
17use crate::methods::gifts::*;
18use crate::methods::inline::*;
19use crate::methods::miniapp::*;
20use crate::methods::passport::*;
21use crate::methods::payments::*;
22use crate::methods::reactions::*;
23use crate::methods::sending::*;
24use crate::methods::stickers::*;
25use crate::methods::stories::*;
26use crate::methods::updates::*;
27use crate::methods::verification::*;
28
29// ─── Wire-format API response ─────────────────────────────────────────────────
30
31// #[serde(bound(...))] overrides the auto-generated bounds so serde does not
32// require T: Default just because the `result` field uses #[serde(default)].
33#[derive(serde::Deserialize)]
34#[serde(bound(deserialize = "T: serde::de::DeserializeOwned"))]
35struct ApiResponse<T> {
36    ok: bool,
37    #[serde(default)]
38    result: Option<T>,
39    description: Option<String>,
40    error_code: Option<u16>,
41    parameters: Option<ResponseParameters>,
42}
43
44#[derive(serde::Deserialize)]
45struct ResponseParameters {
46    migrate_to_chat_id: Option<i64>,
47    retry_after: Option<u32>,
48}
49
50// ─── ClientConfig ─────────────────────────────────────────────────────────────
51
52#[derive(Debug, Clone)]
53/// Configuration for [`BotClient`].
54///
55/// Use the builder methods to customise behaviour, then pass the config to
56/// [`BotClient::new`].
57///
58/// # Example
59///
60/// ```rust,ignore
61/// use std::time::Duration;
62///
63/// let config = ClientConfig::new("123456:ABC...")?
64///     .api_base_url("http://localhost:8081") // local Bot API server
65///     .timeout(Duration::from_secs(60))
66///     .max_retries(5);
67/// ```
68pub struct ClientConfig {
69    /// Bot token used to authenticate with the Telegram API.
70    pub token: String,
71    /// Base URL of the Bot API server (default: `https://api.telegram.org`).
72    pub api_base_url: String,
73    /// Per-request HTTP timeout.
74    pub timeout: Duration,
75    /// Maximum number of automatic retries on flood control responses.
76    pub max_retries: u8,
77}
78
79impl ClientConfig {
80    /// Creates a new `ClientConfig` with the given bot token and default settings.
81    pub fn new(token: impl Into<String>) -> Result<Self> {
82        let token = token.into();
83        validate_token(&token)?;
84        Ok(Self {
85            token,
86            api_base_url: "https://api.telegram.org".to_owned(),
87            timeout: Duration::from_secs(30),
88            max_retries: 3,
89        })
90    }
91
92    /// Sets a custom base URL for API requests, e.g. for a local Bot API server.
93    #[must_use]
94    pub fn api_base_url(mut self, url: impl Into<String>) -> Self {
95        self.api_base_url = url.into();
96        self
97    }
98
99    /// Sets a custom timeout for API requests (default 30 seconds).
100    #[must_use]
101    pub fn timeout(mut self, timeout: Duration) -> Self {
102        self.timeout = timeout;
103        self
104    }
105
106    /// Sets the maximum number of retries on HTTP 429 (flood control) errors (default 3).
107    #[must_use]
108    pub fn max_retries(mut self, n: u8) -> Self {
109        self.max_retries = n;
110        self
111    }
112}
113
114// ─── BotClient ────────────────────────────────────────────────────────────────
115
116struct Inner {
117    http: reqwest::Client,
118    config: ClientConfig,
119}
120
121#[derive(Clone)]
122/// The Telegram Bot API HTTP client.
123///
124/// `BotClient` is cheap to clone — all internal state is reference-counted.
125/// It is safe to share across tasks and threads without additional
126/// synchronisation.
127///
128/// # Creating a client
129///
130/// ```rust,ignore
131/// // From a token string (simplest)
132/// let client = BotClient::from_token("123456:ABC...")?;
133///
134/// // From a ClientConfig for advanced options
135/// let config = ClientConfig::new("123456:ABC...")?
136///     .api_base_url("http://localhost:8081")
137///     .timeout(Duration::from_secs(60));
138/// let client = BotClient::new(config)?;
139/// ```
140///
141/// # Making API calls
142///
143/// Every Bot API method is available as a method on `BotClient`. Each method
144/// returns a builder — set optional parameters with chained calls, then
145/// `.await` to execute:
146///
147/// ```rust,ignore
148/// client
149///     .send_message(chat_id, "Hello!")
150///     .parse_mode(ParseMode::HTML)
151///     .disable_notification(true)
152///     .await?;
153/// ```
154pub struct BotClient {
155    inner: Arc<Inner>,
156}
157
158impl BotClient {
159    /// Creates a new `BotClient` from a [`ClientConfig`].
160    ///
161    /// # Errors
162    ///
163    /// Returns an error if the underlying HTTP client cannot be initialised.
164    pub fn new(config: ClientConfig) -> Result<Self> {
165        let http = reqwest::Client::builder()
166            .timeout(config.timeout)
167            .build()
168            .map_err(Error::Http)?;
169        Ok(Self {
170            inner: Arc::new(Inner { http, config }),
171        })
172    }
173
174    /// Creates a `BotClient` directly from a bot token string.
175    ///
176    /// This is equivalent to `BotClient::new(ClientConfig::new(token)?)`.
177    ///
178    /// # Errors
179    ///
180    /// Returns [`Error::InvalidToken`] if the token format is invalid.
181    pub fn from_token(token: impl Into<String>) -> Result<Self> {
182        Self::new(ClientConfig::new(token)?)
183    }
184
185    /// Returns the bot token used for authentication.
186    #[must_use]
187    pub fn token(&self) -> &str {
188        &self.inner.config.token
189    }
190
191    /// Returns the base URL used for API requests, defaulting to `https://api.telegram.org`.
192    #[must_use]
193    pub fn api_base_url(&self) -> &str {
194        &self.inner.config.api_base_url
195    }
196
197    #[must_use]
198    fn method_url(&self, method: &str) -> String {
199        format!(
200            "{}/bot{}/{}",
201            self.inner.config.api_base_url, self.inner.config.token, method
202        )
203    }
204
205    /// Sends a JSON POST request to a Bot API method and deserialises the result.
206    ///
207    /// Automatically retries on HTTP 429 (flood control) up to `max_retries`
208    /// times, waiting the `retry_after` duration between attempts.
209    ///
210    /// # Errors
211    ///
212    /// Returns an error on network failure, API error (`ok: false`), or
213    /// deserialisation failure.
214    pub async fn post_json<P, R>(&self, method: &str, params: &P) -> Result<R>
215    where
216        P: Serialize + ?Sized,
217        R: DeserializeOwned,
218    {
219        let url = self.method_url(method);
220        let body = serde_json::to_vec(params).map_err(Error::Serialization)?;
221        let max_retries = self.inner.config.max_retries;
222
223        for attempt in 0..=max_retries {
224            debug!("POST {} (attempt {})", method, attempt + 1);
225
226            let resp = self
227                .inner
228                .http
229                .post(&url)
230                .header("Content-Type", "application/json")
231                .body(body.clone())
232                .send()
233                .await
234                .map_err(Error::Http)?;
235
236            let api_resp: ApiResponse<R> = resp
237                .json()
238                .await
239                .map_err(|e| Error::Decode(e.to_string()))?;
240
241            if api_resp.ok {
242                return api_resp
243                    .result
244                    .ok_or_else(|| Error::Decode("ok=true but result is null".to_owned()));
245            }
246
247            let error_code = api_resp.error_code.unwrap_or(0);
248            let description = api_resp
249                .description
250                .unwrap_or_else(|| "Unknown error".to_owned());
251            let retry_after = api_resp.parameters.as_ref().and_then(|p| p.retry_after);
252            let migrate_to_chat_id = api_resp
253                .parameters
254                .as_ref()
255                .and_then(|p| p.migrate_to_chat_id);
256
257            if error_code == 429 {
258                let wait = retry_after.unwrap_or(1);
259                if attempt < max_retries {
260                    warn!(
261                        "Flood control on {}: waiting {}s (attempt {}/{})",
262                        method,
263                        wait,
264                        attempt + 1,
265                        max_retries
266                    );
267                    tokio::time::sleep(Duration::from_secs(u64::from(wait))).await;
268                    continue;
269                }
270                return Err(Error::RateLimit { retry_after: wait });
271            }
272
273            return Err(Error::Api {
274                error_code,
275                description,
276                migrate_to_chat_id,
277                retry_after,
278            });
279        }
280
281        unreachable!()
282    }
283
284    /// Sends a multipart/form-data POST request to a Bot API method and deserialises the result.
285    pub async fn post_multipart<R>(&self, method: &str, form: Form) -> Result<R>
286    where
287        R: DeserializeOwned,
288    {
289        let url = self.method_url(method);
290        debug!("POST multipart {}", method);
291
292        let resp = self
293            .inner
294            .http
295            .post(&url)
296            .multipart(form)
297            .send()
298            .await
299            .map_err(Error::Http)?;
300
301        let api_resp: ApiResponse<R> = resp
302            .json()
303            .await
304            .map_err(|e| Error::Decode(e.to_string()))?;
305
306        if api_resp.ok {
307            return api_resp
308                .result
309                .ok_or_else(|| Error::Decode("ok=true but result is null".to_owned()));
310        }
311
312        let error_code = api_resp.error_code.unwrap_or(0);
313        let description = api_resp
314            .description
315            .unwrap_or_else(|| "Unknown error".to_owned());
316        let retry_after = api_resp.parameters.as_ref().and_then(|p| p.retry_after);
317        let migrate_to_chat_id = api_resp
318            .parameters
319            .as_ref()
320            .and_then(|p| p.migrate_to_chat_id);
321
322        if error_code == 429 {
323            return Err(Error::RateLimit {
324                retry_after: retry_after.unwrap_or(1),
325            });
326        }
327
328        Err(Error::Api {
329            error_code,
330            description,
331            migrate_to_chat_id,
332            retry_after,
333        })
334    }
335
336    /// Downloads a file by its path as returned by [`BotClient::get_file`].
337    ///
338    /// The file path must be obtained by calling `get_file` first:
339    ///
340    /// ```rust,ignore
341    /// let file = client.get_file(&document.file_id).await?;
342    /// let bytes = client.download_file(&file.file_path.unwrap()).await?;
343    /// ```
344    ///
345    /// Maximum file size via the Telegram cloud server is 20 MB.
346    /// Use a [local Bot API server](https://github.com/tdlib/telegram-bot-api)
347    /// to lift this restriction.
348    pub async fn download_file(&self, file_path: &str) -> Result<bytes::Bytes> {
349        let url = format!(
350            "{}/file/bot{}/{}",
351            self.inner.config.api_base_url, self.inner.config.token, file_path
352        );
353        self.inner
354            .http
355            .get(&url)
356            .send()
357            .await
358            .map_err(Error::Http)?
359            .bytes()
360            .await
361            .map_err(Error::Http)
362    }
363
364    // ── Update methods ────────────────────────────────────────────────────────
365
366    /// Calls `getUpdates` — fetches a batch of incoming updates via long polling.
367    pub fn get_updates(&self) -> GetUpdates {
368        GetUpdates::new(self.clone())
369    }
370    /// Calls `setWebhook` — registers a webhook URL with Telegram.
371    pub fn set_webhook(&self, url: impl Into<String>) -> SetWebhook {
372        SetWebhook::new(self.clone(), url)
373    }
374    /// Calls `deleteWebhook` — removes the webhook integration.
375    pub fn delete_webhook(&self) -> DeleteWebhook {
376        DeleteWebhook::new(self.clone())
377    }
378    /// Calls `getWebhookInfo` — returns the current webhook status.
379    pub fn get_webhook_info(&self) -> GetWebhookInfo {
380        GetWebhookInfo::new(self.clone())
381    }
382
383    // ── Getters ───────────────────────────────────────────────────────────────
384
385    /// Calls `getMe` — returns basic information about the bot.
386    pub fn get_me(&self) -> GetMe {
387        GetMe::new(self.clone())
388    }
389    /// Calls `getChat` — returns detailed information about a chat.
390    pub fn get_chat(&self, chat_id: impl Into<rustigram_types::user::ChatId>) -> GetChat {
391        GetChat::new(self.clone(), chat_id)
392    }
393    /// Calls `getChatAdministrators` — returns a list of all chat administrators.
394    pub fn get_chat_administrators(
395        &self,
396        chat_id: impl Into<rustigram_types::user::ChatId>,
397    ) -> GetChatAdministrators {
398        GetChatAdministrators::new(self.clone(), chat_id)
399    }
400    /// Calls `getChatMemberCount` — returns the number of members in a chat.
401    pub fn get_chat_member_count(
402        &self,
403        chat_id: impl Into<rustigram_types::user::ChatId>,
404    ) -> GetChatMemberCount {
405        GetChatMemberCount::new(self.clone(), chat_id)
406    }
407    /// Calls `getChatMember` — returns information about a specific chat member.
408    pub fn get_chat_member(
409        &self,
410        chat_id: impl Into<rustigram_types::user::ChatId>,
411        user_id: i64,
412    ) -> GetChatMember {
413        GetChatMember::new(self.clone(), chat_id, user_id)
414    }
415    /// Calls `getFile` — returns file metadata and a download path.
416    pub fn get_file(&self, file_id: impl Into<String>) -> GetFile {
417        GetFile::new(self.clone(), file_id)
418    }
419    /// Calls `getUserProfilePhotos` — returns a user's profile pictures.
420    pub fn get_user_profile_photos(&self, user_id: i64) -> GetUserProfilePhotos {
421        GetUserProfilePhotos::new(self.clone(), user_id)
422    }
423    /// Calls `getUserProfileAudios` — returns audios displayed on a user's profile (Bot API 9.4).
424    pub fn get_user_profile_audios(&self, user_id: i64) -> GetUserProfileAudios {
425        GetUserProfileAudios::new(self.clone(), user_id)
426    }
427    /// Calls `getUserPersonalChatMessages` — returns the last messages from a user's personal chat (Bot API 9.7).
428    ///
429    /// `limit` must be between 1 and 20.
430    pub fn get_user_personal_chat_messages(
431        &self,
432        user_id: i64,
433        limit: u32,
434    ) -> GetUserPersonalChatMessages {
435        GetUserPersonalChatMessages::new(self.clone(), user_id, limit)
436    }
437
438    // ── Sending ───────────────────────────────────────────────────────────────
439
440    /// Calls `sendMessage` — sends a text message to a chat.
441    pub fn send_message(
442        &self,
443        chat_id: impl Into<rustigram_types::user::ChatId>,
444        text: impl Into<String>,
445    ) -> SendMessage {
446        SendMessage::new(self.clone(), chat_id, text)
447    }
448    /// Calls `forwardMessage` — forwards a message from one chat to another.
449    pub fn forward_message(
450        &self,
451        chat_id: impl Into<rustigram_types::user::ChatId>,
452        from_chat_id: impl Into<rustigram_types::user::ChatId>,
453        message_id: i64,
454    ) -> ForwardMessage {
455        ForwardMessage::new(self.clone(), chat_id, from_chat_id, message_id)
456    }
457    /// Calls `copyMessage` — copies a message without the forward header.
458    pub fn copy_message(
459        &self,
460        chat_id: impl Into<rustigram_types::user::ChatId>,
461        from_chat_id: impl Into<rustigram_types::user::ChatId>,
462        message_id: i64,
463    ) -> CopyMessage {
464        CopyMessage::new(self.clone(), chat_id, from_chat_id, message_id)
465    }
466    /// Calls `sendChatAction` — displays a typing or upload indicator.
467    pub fn send_chat_action(
468        &self,
469        chat_id: impl Into<rustigram_types::user::ChatId>,
470        action: ChatAction,
471    ) -> SendChatAction {
472        SendChatAction::new(self.clone(), chat_id, action)
473    }
474    /// Calls `sendPhoto` — sends a photo.
475    pub fn send_photo(
476        &self,
477        chat_id: impl Into<rustigram_types::user::ChatId>,
478        photo: rustigram_types::file::InputFile,
479    ) -> SendPhoto {
480        SendPhoto::new(self.clone(), chat_id, photo)
481    }
482    /// Calls `sendLivePhoto` — sends a live photo (Bot API 9.7).
483    ///
484    /// `live_photo` is the video component; `photo` is the static preview.
485    /// Sending by URL is currently unsupported — use `InputFile::FileId` or `InputFile::Bytes`.
486    pub fn send_live_photo(
487        &self,
488        chat_id: impl Into<rustigram_types::user::ChatId>,
489        live_photo: rustigram_types::file::InputFile,
490        photo: rustigram_types::file::InputFile,
491    ) -> SendLivePhoto {
492        SendLivePhoto::new(self.clone(), chat_id, live_photo, photo)
493    }
494
495    /// Calls `sendAudio` — sends an audio file treated as music.
496    pub fn send_audio(
497        &self,
498        chat_id: impl Into<rustigram_types::user::ChatId>,
499        audio: rustigram_types::file::InputFile,
500    ) -> SendAudio {
501        SendAudio::new(self.clone(), chat_id, audio)
502    }
503    /// Calls `sendDocument` — sends a general file.
504    pub fn send_document(
505        &self,
506        chat_id: impl Into<rustigram_types::user::ChatId>,
507        document: rustigram_types::file::InputFile,
508    ) -> SendDocument {
509        SendDocument::new(self.clone(), chat_id, document)
510    }
511    /// Calls `sendVideo` — sends a video file.
512    pub fn send_video(
513        &self,
514        chat_id: impl Into<rustigram_types::user::ChatId>,
515        video: rustigram_types::file::InputFile,
516    ) -> SendVideo {
517        SendVideo::new(self.clone(), chat_id, video)
518    }
519    /// Calls `sendAnimation` — sends a GIF or silent H.264 video.
520    pub fn send_animation(
521        &self,
522        chat_id: impl Into<rustigram_types::user::ChatId>,
523        animation: rustigram_types::file::InputFile,
524    ) -> SendAnimation {
525        SendAnimation::new(self.clone(), chat_id, animation)
526    }
527    /// Calls `sendVoice` — sends a voice note.
528    pub fn send_voice(
529        &self,
530        chat_id: impl Into<rustigram_types::user::ChatId>,
531        voice: rustigram_types::file::InputFile,
532    ) -> SendVoice {
533        SendVoice::new(self.clone(), chat_id, voice)
534    }
535    /// Calls `sendVideoNote` — sends a rounded-square video.
536    pub fn send_video_note(
537        &self,
538        chat_id: impl Into<rustigram_types::user::ChatId>,
539        video_note: rustigram_types::file::InputFile,
540    ) -> SendVideoNote {
541        SendVideoNote::new(self.clone(), chat_id, video_note)
542    }
543    /// Calls `sendSticker` — sends a sticker.
544    pub fn send_sticker(
545        &self,
546        chat_id: impl Into<rustigram_types::user::ChatId>,
547        sticker: rustigram_types::file::InputFile,
548    ) -> SendSticker {
549        SendSticker::new(self.clone(), chat_id, sticker)
550    }
551    /// Calls `sendLocation` — sends a geographic location, optionally live.
552    pub fn send_location(
553        &self,
554        chat_id: impl Into<rustigram_types::user::ChatId>,
555        latitude: f64,
556        longitude: f64,
557    ) -> SendLocation {
558        SendLocation::new(self.clone(), chat_id, latitude, longitude)
559    }
560    /// Calls `sendContact` — sends a phone contact.
561    pub fn send_contact(
562        &self,
563        chat_id: impl Into<rustigram_types::user::ChatId>,
564        phone_number: impl Into<String>,
565        first_name: impl Into<String>,
566    ) -> SendContact {
567        SendContact::new(self.clone(), chat_id, phone_number, first_name)
568    }
569    /// Calls `sendPoll` — sends a native poll or quiz.
570    pub fn send_poll(
571        &self,
572        chat_id: impl Into<rustigram_types::user::ChatId>,
573        question: impl Into<String>,
574        options: Vec<rustigram_types::poll::InputPollOption>,
575    ) -> SendPoll {
576        SendPoll::new(self.clone(), chat_id, question, options)
577    }
578    /// Calls `sendDice` — sends an animated random emoji.
579    pub fn send_dice(&self, chat_id: impl Into<rustigram_types::user::ChatId>) -> SendDice {
580        SendDice::new(self.clone(), chat_id)
581    }
582    /// Calls `sendVenue` — sends information about a venue.
583    pub fn send_venue(
584        &self,
585        chat_id: impl Into<rustigram_types::user::ChatId>,
586        latitude: f64,
587        longitude: f64,
588        title: impl Into<String>,
589        address: impl Into<String>,
590    ) -> SendVenue {
591        SendVenue::new(self.clone(), chat_id, latitude, longitude, title, address)
592    }
593    /// Calls `forwardMessages` — forwards 1–100 messages at once, preserving album grouping.
594    pub fn forward_messages(
595        &self,
596        chat_id: impl Into<rustigram_types::user::ChatId>,
597        from_chat_id: impl Into<rustigram_types::user::ChatId>,
598        message_ids: Vec<i64>,
599    ) -> ForwardMessages {
600        ForwardMessages::new(self.clone(), chat_id, from_chat_id, message_ids)
601    }
602    /// Calls `copyMessages` — copies 1–100 messages without a forward link, preserving album grouping.
603    pub fn copy_messages(
604        &self,
605        chat_id: impl Into<rustigram_types::user::ChatId>,
606        from_chat_id: impl Into<rustigram_types::user::ChatId>,
607        message_ids: Vec<i64>,
608    ) -> CopyMessages {
609        CopyMessages::new(self.clone(), chat_id, from_chat_id, message_ids)
610    }
611    /// Calls `sendMediaGroup` — sends 2–10 photos, videos, documents, or audios as an album.
612    ///
613    /// The `media` parameter accepts `Vec<serde_json::Value>` until the `InputMedia` enum
614    /// is defined in Priority 4.
615    pub fn send_media_group(
616        &self,
617        chat_id: impl Into<rustigram_types::user::ChatId>,
618        media: Vec<serde_json::Value>,
619    ) -> SendMediaGroup {
620        SendMediaGroup::new(self.clone(), chat_id, media)
621    }
622    /// Calls `sendPaidMedia` — sends paid media requiring Telegram Stars to view.
623    ///
624    /// The `media` parameter accepts `Vec<serde_json::Value>` until the `InputPaidMedia` enum
625    /// is defined in Priority 4.
626    pub fn send_paid_media(
627        &self,
628        chat_id: impl Into<rustigram_types::user::ChatId>,
629        star_count: u32,
630        media: Vec<serde_json::Value>,
631    ) -> SendPaidMedia {
632        SendPaidMedia::new(self.clone(), chat_id, star_count, media)
633    }
634    /// Calls `sendGame` — sends an HTML5 game.
635    pub fn send_game(&self, chat_id: i64, game_short_name: impl Into<String>) -> SendGame {
636        SendGame::new(self.clone(), chat_id, game_short_name)
637    }
638    /// Calls `sendChecklist` — sends a checklist on behalf of a business account.
639    pub fn send_checklist(
640        &self,
641        business_connection_id: impl Into<String>,
642        chat_id: i64,
643        checklist: rustigram_types::checklist::InputChecklist,
644    ) -> SendChecklist {
645        SendChecklist::new(self.clone(), business_connection_id, chat_id, checklist)
646    }
647    /// Calls `sendMessageDraft` — streams a partial message (Bot API 9.5+).
648    pub fn send_message_draft(
649        &self,
650        chat_id: impl Into<rustigram_types::user::ChatId>,
651        draft_id: i64,
652        text: impl Into<String>,
653    ) -> SendMessageDraft {
654        SendMessageDraft::new(self.clone(), chat_id, draft_id, text)
655    }
656    /// Calls `sendRichMessage` — sends a rich formatted message (Bot API 10.1).
657    pub fn send_rich_message(
658        &self,
659        chat_id: impl Into<rustigram_types::user::ChatId>,
660        rich_message: rustigram_types::rich_message::InputRichMessage,
661    ) -> SendRichMessage {
662        SendRichMessage::new(self.clone(), chat_id, rich_message)
663    }
664    /// Calls `sendRichMessageDraft` — streams a partial rich message as an ephemeral preview (Bot API 10.1).
665    ///
666    /// The draft expires after 30 seconds. Call [`send_rich_message`](Self::send_rich_message)
667    /// with the completed content to persist it.
668    pub fn send_rich_message_draft(
669        &self,
670        chat_id: i64,
671        draft_id: i64,
672        rich_message: rustigram_types::rich_message::InputRichMessage,
673    ) -> SendRichMessageDraft {
674        SendRichMessageDraft::new(self.clone(), chat_id, draft_id, rich_message)
675    }
676    /// Calls `deleteMessage` — deletes a message.
677    pub fn delete_message(
678        &self,
679        chat_id: impl Into<rustigram_types::user::ChatId>,
680        message_id: i64,
681    ) -> DeleteMessage {
682        DeleteMessage::new(self.clone(), chat_id, message_id)
683    }
684    /// Calls `deleteMessages` — deletes up to 100 messages at once.
685    pub fn delete_messages(
686        &self,
687        chat_id: impl Into<rustigram_types::user::ChatId>,
688        message_ids: Vec<i64>,
689    ) -> DeleteMessages {
690        DeleteMessages::new(self.clone(), chat_id, message_ids)
691    }
692    /// Calls `deleteEphemeralMessage` — deletes an ephemeral message (Bot API 10.2).
693    pub fn delete_ephemeral_message(
694        &self,
695        chat_id: impl Into<rustigram_types::user::ChatId>,
696        receiver_user_id: i64,
697        ephemeral_message_id: i64,
698    ) -> DeleteEphemeralMessage {
699        DeleteEphemeralMessage::new(
700            self.clone(),
701            chat_id,
702            receiver_user_id,
703            ephemeral_message_id,
704        )
705    }
706    /// Calls `stopPoll` — stops an open poll.
707    pub fn stop_poll(
708        &self,
709        chat_id: impl Into<rustigram_types::user::ChatId>,
710        message_id: i64,
711    ) -> StopPoll {
712        StopPoll::new(self.clone(), chat_id, message_id)
713    }
714    /// Calls `answerCallbackQuery` — acknowledges a callback button press.
715    pub fn answer_callback_query(
716        &self,
717        callback_query_id: impl Into<String>,
718    ) -> AnswerCallbackQuery {
719        AnswerCallbackQuery::new(self.clone(), callback_query_id)
720    }
721
722    // ── Editing ───────────────────────────────────────────────────────────────
723
724    /// Calls `editMessageText` — edits the text of a sent message.
725    pub fn edit_message_text(
726        &self,
727        chat_id: impl Into<rustigram_types::user::ChatId>,
728        message_id: i64,
729        text: impl Into<String>,
730    ) -> EditMessageText {
731        EditMessageText::in_chat(self.clone(), chat_id, message_id, text)
732    }
733    /// Calls `editMessageText` for an inline message sent via inline mode.
734    pub fn edit_inline_message_text(
735        &self,
736        inline_message_id: impl Into<String>,
737        text: impl Into<String>,
738    ) -> EditMessageText {
739        EditMessageText::inline(self.clone(), inline_message_id, text)
740    }
741    /// Calls `editMessageText` to replace a chat message with rich formatted content.
742    pub fn edit_message_rich_text(
743        &self,
744        chat_id: impl Into<rustigram_types::user::ChatId>,
745        message_id: i64,
746        rich_message: rustigram_types::rich_message::InputRichMessage,
747    ) -> EditMessageText {
748        EditMessageText::in_chat_rich(self.clone(), chat_id, message_id, rich_message)
749    }
750    /// Calls `editMessageText` to replace an inline message with rich formatted content.
751    pub fn edit_inline_message_rich_text(
752        &self,
753        inline_message_id: impl Into<String>,
754        rich_message: rustigram_types::rich_message::InputRichMessage,
755    ) -> EditMessageText {
756        EditMessageText::inline_rich(self.clone(), inline_message_id, rich_message)
757    }
758    /// Calls `editMessageCaption` — edits the caption of a media message.
759    pub fn edit_message_caption(
760        &self,
761        chat_id: impl Into<rustigram_types::user::ChatId>,
762        message_id: i64,
763    ) -> EditMessageCaption {
764        EditMessageCaption::in_chat(self.clone(), chat_id, message_id)
765    }
766    /// Calls `editMessageCaption` for an inline message sent via inline mode.
767    pub fn edit_inline_message_caption(
768        &self,
769        inline_message_id: impl Into<String>,
770    ) -> EditMessageCaption {
771        EditMessageCaption::inline(self.clone(), inline_message_id)
772    }
773    /// Calls `editMessageMedia` — replaces the media content of a message.
774    ///
775    /// The `media` parameter accepts `serde_json::Value` until `InputMedia` is
776    /// defined in Priority 4.
777    pub fn edit_message_media(
778        &self,
779        chat_id: impl Into<rustigram_types::user::ChatId>,
780        message_id: i64,
781        media: serde_json::Value,
782    ) -> EditMessageMedia {
783        EditMessageMedia::in_chat(self.clone(), chat_id, message_id, media)
784    }
785    /// Calls `editMessageMedia` for an inline message sent via inline mode.
786    pub fn edit_inline_message_media(
787        &self,
788        inline_message_id: impl Into<String>,
789        media: serde_json::Value,
790    ) -> EditMessageMedia {
791        EditMessageMedia::inline(self.clone(), inline_message_id, media)
792    }
793    /// Calls `editMessageReplyMarkup` — replaces the inline keyboard of a message.
794    pub fn edit_message_reply_markup(
795        &self,
796        chat_id: impl Into<rustigram_types::user::ChatId>,
797        message_id: i64,
798    ) -> EditMessageReplyMarkup {
799        EditMessageReplyMarkup::in_chat(self.clone(), chat_id, message_id)
800    }
801    /// Calls `editMessageReplyMarkup` for an inline message sent via inline mode.
802    pub fn edit_inline_message_reply_markup(
803        &self,
804        inline_message_id: impl Into<String>,
805    ) -> EditMessageReplyMarkup {
806        EditMessageReplyMarkup::inline(self.clone(), inline_message_id)
807    }
808    /// Calls `editEphemeralMessageText` — edits the text of an ephemeral message (Bot API 10.2).
809    pub fn edit_ephemeral_message_text(
810        &self,
811        chat_id: impl Into<rustigram_types::user::ChatId>,
812        receiver_user_id: i64,
813        ephemeral_message_id: i64,
814        text: impl Into<String>,
815    ) -> EditEphemeralMessageText {
816        EditEphemeralMessageText::new(
817            self.clone(),
818            chat_id,
819            receiver_user_id,
820            ephemeral_message_id,
821            text,
822        )
823    }
824    /// Calls `editEphemeralMessageCaption` — edits the caption of an ephemeral message (Bot API 10.2).
825    pub fn edit_ephemeral_message_caption(
826        &self,
827        chat_id: impl Into<rustigram_types::user::ChatId>,
828        receiver_user_id: i64,
829        ephemeral_message_id: i64,
830    ) -> EditEphemeralMessageCaption {
831        EditEphemeralMessageCaption::new(
832            self.clone(),
833            chat_id,
834            receiver_user_id,
835            ephemeral_message_id,
836        )
837    }
838    /// Calls `editEphemeralMessageReplyMarkup` — replaces the inline keyboard of an
839    /// ephemeral message (Bot API 10.2).
840    pub fn edit_ephemeral_message_reply_markup(
841        &self,
842        chat_id: impl Into<rustigram_types::user::ChatId>,
843        receiver_user_id: i64,
844        ephemeral_message_id: i64,
845    ) -> EditEphemeralMessageReplyMarkup {
846        EditEphemeralMessageReplyMarkup::new(
847            self.clone(),
848            chat_id,
849            receiver_user_id,
850            ephemeral_message_id,
851        )
852    }
853    /// Calls `editMessageChecklist` — edits a checklist on behalf of a business account.
854    pub fn edit_message_checklist(
855        &self,
856        business_connection_id: impl Into<String>,
857        chat_id: i64,
858        message_id: i64,
859        checklist: rustigram_types::checklist::InputChecklist,
860    ) -> EditMessageChecklist {
861        EditMessageChecklist::new(
862            self.clone(),
863            business_connection_id,
864            chat_id,
865            message_id,
866            checklist,
867        )
868    }
869    /// Calls `approveSuggestedPost` — approves a suggested post in a direct messages chat.
870    pub fn approve_suggested_post(&self, chat_id: i64, message_id: i64) -> ApproveSuggestedPost {
871        ApproveSuggestedPost::new(self.clone(), chat_id, message_id)
872    }
873    /// Calls `declineSuggestedPost` — declines a suggested post in a direct messages chat.
874    pub fn decline_suggested_post(&self, chat_id: i64, message_id: i64) -> DeclineSuggestedPost {
875        DeclineSuggestedPost::new(self.clone(), chat_id, message_id)
876    }
877    /// Calls `editMessageLiveLocation` — updates the position of a live location.
878    pub fn edit_message_live_location(
879        &self,
880        chat_id: impl Into<rustigram_types::user::ChatId>,
881        message_id: i64,
882        latitude: f64,
883        longitude: f64,
884    ) -> EditMessageLiveLocation {
885        EditMessageLiveLocation::in_chat(self.clone(), chat_id, message_id, latitude, longitude)
886    }
887    /// Calls `editMessageLiveLocation` for an inline message sent via inline mode.
888    pub fn edit_inline_message_live_location(
889        &self,
890        inline_message_id: impl Into<String>,
891        latitude: f64,
892        longitude: f64,
893    ) -> EditMessageLiveLocation {
894        EditMessageLiveLocation::inline(self.clone(), inline_message_id, latitude, longitude)
895    }
896    /// Calls `stopMessageLiveLocation` — stops a live location from updating.
897    pub fn stop_message_live_location(
898        &self,
899        chat_id: impl Into<rustigram_types::user::ChatId>,
900        message_id: i64,
901    ) -> StopMessageLiveLocation {
902        StopMessageLiveLocation::in_chat(self.clone(), chat_id, message_id)
903    }
904    /// Calls `stopMessageLiveLocation` for an inline message sent via inline mode.
905    pub fn stop_inline_message_live_location(
906        &self,
907        inline_message_id: impl Into<String>,
908    ) -> StopMessageLiveLocation {
909        StopMessageLiveLocation::inline(self.clone(), inline_message_id)
910    }
911
912    // ── Chat management ───────────────────────────────────────────────────────
913
914    /// Calls `banChatMember` — bans a user from a chat.
915    pub fn ban_chat_member(
916        &self,
917        chat_id: impl Into<rustigram_types::user::ChatId>,
918        user_id: i64,
919    ) -> BanChatMember {
920        BanChatMember::new(self.clone(), chat_id, user_id)
921    }
922    /// Calls `unbanChatMember` — lifts a ban from a user.
923    pub fn unban_chat_member(
924        &self,
925        chat_id: impl Into<rustigram_types::user::ChatId>,
926        user_id: i64,
927    ) -> UnbanChatMember {
928        UnbanChatMember::new(self.clone(), chat_id, user_id)
929    }
930    /// Calls `restrictChatMember` — restricts what a user can do in a chat.
931    pub fn restrict_chat_member(
932        &self,
933        chat_id: impl Into<rustigram_types::user::ChatId>,
934        user_id: i64,
935        permissions: rustigram_types::chat::ChatPermissions,
936    ) -> RestrictChatMember {
937        RestrictChatMember::new(self.clone(), chat_id, user_id, permissions)
938    }
939    /// Calls `promoteChatMember` — grants or revokes admin privileges.
940    pub fn promote_chat_member(
941        &self,
942        chat_id: impl Into<rustigram_types::user::ChatId>,
943        user_id: i64,
944    ) -> PromoteChatMember {
945        PromoteChatMember::new(self.clone(), chat_id, user_id)
946    }
947    /// Calls `setChatAdministratorCustomTitle` — sets a custom title for an admin.
948    pub fn set_chat_administrator_custom_title(
949        &self,
950        chat_id: impl Into<rustigram_types::user::ChatId>,
951        user_id: i64,
952        custom_title: impl Into<String>,
953    ) -> SetChatAdministratorCustomTitle {
954        SetChatAdministratorCustomTitle::new(self.clone(), chat_id, user_id, custom_title)
955    }
956    /// Calls `setChatMemberTag` — sets a tag for a regular member (Bot API 9.5).
957    pub fn set_chat_member_tag(
958        &self,
959        chat_id: impl Into<rustigram_types::user::ChatId>,
960        user_id: i64,
961    ) -> SetChatMemberTag {
962        SetChatMemberTag::new(self.clone(), chat_id, user_id)
963    }
964    /// Calls `setChatPermissions` — sets default chat permissions for all members.
965    pub fn set_chat_permissions(
966        &self,
967        chat_id: impl Into<rustigram_types::user::ChatId>,
968        permissions: rustigram_types::chat::ChatPermissions,
969    ) -> SetChatPermissions {
970        SetChatPermissions::new(self.clone(), chat_id, permissions)
971    }
972    /// Calls `exportChatInviteLink` — generates a new primary invite link, revoking the old one.
973    pub fn export_chat_invite_link(
974        &self,
975        chat_id: impl Into<rustigram_types::user::ChatId>,
976    ) -> ExportChatInviteLink {
977        ExportChatInviteLink::new(self.clone(), chat_id)
978    }
979    /// Calls `createChatInviteLink` — generates a new additional invite link.
980    pub fn create_chat_invite_link(
981        &self,
982        chat_id: impl Into<rustigram_types::user::ChatId>,
983    ) -> CreateChatInviteLink {
984        CreateChatInviteLink::new(self.clone(), chat_id)
985    }
986    /// Calls `editChatInviteLink` — edits a non-primary invite link created by the bot.
987    pub fn edit_chat_invite_link(
988        &self,
989        chat_id: impl Into<rustigram_types::user::ChatId>,
990        invite_link: impl Into<String>,
991    ) -> EditChatInviteLink {
992        EditChatInviteLink::new(self.clone(), chat_id, invite_link)
993    }
994    /// Calls `revokeChatInviteLink` — revokes an invite link created by the bot.
995    pub fn revoke_chat_invite_link(
996        &self,
997        chat_id: impl Into<rustigram_types::user::ChatId>,
998        invite_link: impl Into<String>,
999    ) -> RevokeChatInviteLink {
1000        RevokeChatInviteLink::new(self.clone(), chat_id, invite_link)
1001    }
1002    /// Calls `createChatSubscriptionInviteLink` — creates a subscription invite link for a channel.
1003    pub fn create_chat_subscription_invite_link(
1004        &self,
1005        chat_id: impl Into<rustigram_types::user::ChatId>,
1006        subscription_period: u32,
1007        subscription_price: u32,
1008    ) -> CreateChatSubscriptionInviteLink {
1009        CreateChatSubscriptionInviteLink::new(
1010            self.clone(),
1011            chat_id,
1012            subscription_period,
1013            subscription_price,
1014        )
1015    }
1016    /// Calls `editChatSubscriptionInviteLink` — edits a subscription invite link.
1017    pub fn edit_chat_subscription_invite_link(
1018        &self,
1019        chat_id: impl Into<rustigram_types::user::ChatId>,
1020        invite_link: impl Into<String>,
1021    ) -> EditChatSubscriptionInviteLink {
1022        EditChatSubscriptionInviteLink::new(self.clone(), chat_id, invite_link)
1023    }
1024    /// Calls `approveChatJoinRequest` — approves a pending join request.
1025    pub fn approve_chat_join_request(
1026        &self,
1027        chat_id: impl Into<rustigram_types::user::ChatId>,
1028        user_id: i64,
1029    ) -> ApproveChatJoinRequest {
1030        ApproveChatJoinRequest::new(self.clone(), chat_id, user_id)
1031    }
1032    /// Calls `declineChatJoinRequest` — declines a pending join request.
1033    pub fn decline_chat_join_request(
1034        &self,
1035        chat_id: impl Into<rustigram_types::user::ChatId>,
1036        user_id: i64,
1037    ) -> DeclineChatJoinRequest {
1038        DeclineChatJoinRequest::new(self.clone(), chat_id, user_id)
1039    }
1040    /// Calls `answerChatJoinRequestQuery` — processes a join request query (Bot API 10.1).
1041    ///
1042    /// Must be called within 10 seconds of receiving a [`ChatJoinRequest`](rustigram_types::ChatJoinRequest)
1043    /// that carries a `query_id`.
1044    pub fn answer_chat_join_request_query(
1045        &self,
1046        chat_join_request_query_id: impl Into<String>,
1047        result: crate::methods::chat_management::JoinRequestResult,
1048    ) -> AnswerChatJoinRequestQuery {
1049        AnswerChatJoinRequestQuery::new(self.clone(), chat_join_request_query_id, result)
1050    }
1051    /// Calls `sendChatJoinRequestWebApp` — shows a Mini App to the user before deciding (Bot API 10.1).
1052    ///
1053    /// Must be called within 10 seconds of receiving a [`ChatJoinRequest`](rustigram_types::ChatJoinRequest)
1054    /// that carries a `query_id`.
1055    pub fn send_chat_join_request_web_app(
1056        &self,
1057        chat_join_request_query_id: impl Into<String>,
1058        web_app_url: impl Into<String>,
1059    ) -> SendChatJoinRequestWebApp {
1060        SendChatJoinRequestWebApp::new(self.clone(), chat_join_request_query_id, web_app_url)
1061    }
1062    /// Calls `banChatSenderChat` — bans a channel chat from sending in a supergroup or channel.
1063    pub fn ban_chat_sender_chat(
1064        &self,
1065        chat_id: impl Into<rustigram_types::user::ChatId>,
1066        sender_chat_id: i64,
1067    ) -> BanChatSenderChat {
1068        BanChatSenderChat::new(self.clone(), chat_id, sender_chat_id)
1069    }
1070    /// Calls `unbanChatSenderChat` — unbans a previously banned channel chat.
1071    pub fn unban_chat_sender_chat(
1072        &self,
1073        chat_id: impl Into<rustigram_types::user::ChatId>,
1074        sender_chat_id: i64,
1075    ) -> UnbanChatSenderChat {
1076        UnbanChatSenderChat::new(self.clone(), chat_id, sender_chat_id)
1077    }
1078    /// Calls `unpinAllChatMessages` — clears all pinned messages in a chat.
1079    pub fn unpin_all_chat_messages(
1080        &self,
1081        chat_id: impl Into<rustigram_types::user::ChatId>,
1082    ) -> UnpinAllChatMessages {
1083        UnpinAllChatMessages::new(self.clone(), chat_id)
1084    }
1085    /// Calls `setChatPhoto` — sets a new profile photo for the chat.
1086    pub fn set_chat_photo(
1087        &self,
1088        chat_id: impl Into<rustigram_types::user::ChatId>,
1089        photo: rustigram_types::file::InputFile,
1090    ) -> SetChatPhoto {
1091        SetChatPhoto::new(self.clone(), chat_id, photo)
1092    }
1093    /// Calls `deleteChatPhoto` — deletes the chat photo.
1094    pub fn delete_chat_photo(
1095        &self,
1096        chat_id: impl Into<rustigram_types::user::ChatId>,
1097    ) -> DeleteChatPhoto {
1098        DeleteChatPhoto::new(self.clone(), chat_id)
1099    }
1100    /// Calls `setChatTitle` — changes the title of a chat.
1101    pub fn set_chat_title(
1102        &self,
1103        chat_id: impl Into<rustigram_types::user::ChatId>,
1104        title: impl Into<String>,
1105    ) -> SetChatTitle {
1106        SetChatTitle::new(self.clone(), chat_id, title)
1107    }
1108    /// Calls `setChatDescription` — changes the description of a group, supergroup, or channel.
1109    pub fn set_chat_description(
1110        &self,
1111        chat_id: impl Into<rustigram_types::user::ChatId>,
1112    ) -> SetChatDescription {
1113        SetChatDescription::new(self.clone(), chat_id)
1114    }
1115    /// Calls `setChatStickerSet` — sets the sticker set for a supergroup.
1116    pub fn set_chat_sticker_set(
1117        &self,
1118        chat_id: impl Into<rustigram_types::user::ChatId>,
1119        sticker_set_name: impl Into<String>,
1120    ) -> SetChatStickerSet {
1121        SetChatStickerSet::new(self.clone(), chat_id, sticker_set_name)
1122    }
1123    /// Calls `deleteChatStickerSet` — removes the sticker set from a supergroup.
1124    pub fn delete_chat_sticker_set(
1125        &self,
1126        chat_id: impl Into<rustigram_types::user::ChatId>,
1127    ) -> DeleteChatStickerSet {
1128        DeleteChatStickerSet::new(self.clone(), chat_id)
1129    }
1130    /// Calls `leaveChat` — makes the bot leave a group, supergroup, or channel.
1131    pub fn leave_chat(&self, chat_id: impl Into<rustigram_types::user::ChatId>) -> LeaveChat {
1132        LeaveChat::new(self.clone(), chat_id)
1133    }
1134    /// Calls `getUserChatBoosts` — returns the boosts added to a chat by a user.
1135    pub fn get_user_chat_boosts(
1136        &self,
1137        chat_id: impl Into<rustigram_types::user::ChatId>,
1138        user_id: i64,
1139    ) -> GetUserChatBoosts {
1140        GetUserChatBoosts::new(self.clone(), chat_id, user_id)
1141    }
1142    /// Calls `pinChatMessage` — pins a message in a chat.
1143    pub fn pin_chat_message(
1144        &self,
1145        chat_id: impl Into<rustigram_types::user::ChatId>,
1146        message_id: i64,
1147    ) -> PinChatMessage {
1148        PinChatMessage::new(self.clone(), chat_id, message_id)
1149    }
1150    /// Calls `unpinChatMessage` — unpins a message in a chat.
1151    pub fn unpin_chat_message(
1152        &self,
1153        chat_id: impl Into<rustigram_types::user::ChatId>,
1154    ) -> UnpinChatMessage {
1155        UnpinChatMessage::new(self.clone(), chat_id)
1156    }
1157
1158    // ── Bot settings ──────────────────────────────────────────────────────────
1159
1160    /// Calls `logOut` — logs the bot out of the cloud Bot API server.
1161    pub fn log_out(&self) -> LogOut {
1162        LogOut::new(self.clone())
1163    }
1164    /// Calls `close` — closes the bot instance before moving it to another server.
1165    pub fn close(&self) -> Close {
1166        Close::new(self.clone())
1167    }
1168    /// Calls `setMyCommands` — sets the bot's command list.
1169    pub fn set_my_commands(
1170        &self,
1171        commands: Vec<rustigram_types::user::BotCommand>,
1172    ) -> SetMyCommands {
1173        SetMyCommands::new(self.clone(), commands)
1174    }
1175    /// Calls `deleteMyCommands` — deletes the bot's command list for a given scope and language.
1176    pub fn delete_my_commands(&self) -> DeleteMyCommands {
1177        DeleteMyCommands::new(self.clone())
1178    }
1179    /// Calls `getMyCommands` — returns the bot's current command list.
1180    pub fn get_my_commands(&self) -> GetMyCommands {
1181        GetMyCommands::new(self.clone())
1182    }
1183    /// Calls `setMyName` — changes the bot's display name.
1184    pub fn set_my_name(&self) -> SetMyName {
1185        SetMyName::new(self.clone())
1186    }
1187    /// Calls `getMyName` — returns the bot's current display name.
1188    pub fn get_my_name(&self) -> GetMyName {
1189        GetMyName::new(self.clone())
1190    }
1191    /// Calls `setMyDescription` — changes the bot's profile description.
1192    pub fn set_my_description(&self) -> SetMyDescription {
1193        SetMyDescription::new(self.clone())
1194    }
1195    /// Calls `getMyDescription` — returns the bot's current profile description.
1196    pub fn get_my_description(&self) -> GetMyDescription {
1197        GetMyDescription::new(self.clone())
1198    }
1199    /// Calls `setMyShortDescription` — changes the bot's short description.
1200    pub fn set_my_short_description(&self) -> SetMyShortDescription {
1201        SetMyShortDescription::new(self.clone())
1202    }
1203    /// Calls `getMyShortDescription` — returns the bot's current short description.
1204    pub fn get_my_short_description(&self) -> GetMyShortDescription {
1205        GetMyShortDescription::new(self.clone())
1206    }
1207    /// Calls `setMyDefaultAdministratorRights` — sets the default admin rights suggested to users.
1208    pub fn set_my_default_administrator_rights(&self) -> SetMyDefaultAdministratorRights {
1209        SetMyDefaultAdministratorRights::new(self.clone())
1210    }
1211    /// Calls `getMyDefaultAdministratorRights` — returns the bot's current default admin rights.
1212    pub fn get_my_default_administrator_rights(&self) -> GetMyDefaultAdministratorRights {
1213        GetMyDefaultAdministratorRights::new(self.clone())
1214    }
1215    /// Calls `getChatMenuButton` — returns the current menu button for a private chat.
1216    pub fn get_chat_menu_button(&self) -> GetChatMenuButton {
1217        GetChatMenuButton::new(self.clone())
1218    }
1219    /// Calls `setChatMenuButton` — changes the bot's menu button in a private chat or globally.
1220    pub fn set_chat_menu_button(&self) -> SetChatMenuButton {
1221        SetChatMenuButton::new(self.clone())
1222    }
1223    /// Calls `setMyProfilePhoto` — changes the bot's profile photo (Bot API 9.4).
1224    ///
1225    /// Pass a pre-serialised `InputProfilePhoto` JSON string.
1226    pub fn set_my_profile_photo(&self, photo_json: impl Into<String>) -> SetMyProfilePhoto {
1227        SetMyProfilePhoto::new(self.clone(), photo_json.into())
1228    }
1229    /// Calls `removeMyProfilePhoto` — removes the bot's current profile photo (Bot API 9.4).
1230    pub fn remove_my_profile_photo(&self) -> RemoveMyProfilePhoto {
1231        RemoveMyProfilePhoto::new(self.clone())
1232    }
1233    /// Calls `getManagedBotToken` — returns the token of a managed bot (Bot API 9.6).
1234    pub fn get_managed_bot_token(&self, user_id: i64) -> GetManagedBotToken {
1235        GetManagedBotToken::new(self.clone(), user_id)
1236    }
1237    /// Calls `replaceManagedBotToken` — revokes and regenerates a managed bot's token (Bot API 9.6).
1238    pub fn replace_managed_bot_token(&self, user_id: i64) -> ReplaceManagedBotToken {
1239        ReplaceManagedBotToken::new(self.clone(), user_id)
1240    }
1241    /// Calls `getManagedBotAccessSettings` — returns the access settings of a managed bot (Bot API 9.7).
1242    pub fn get_managed_bot_access_settings(&self, user_id: i64) -> GetManagedBotAccessSettings {
1243        GetManagedBotAccessSettings::new(self.clone(), user_id)
1244    }
1245    /// Calls `setManagedBotAccessSettings` — changes the access settings of a managed bot (Bot API 9.7).
1246    pub fn set_managed_bot_access_settings(
1247        &self,
1248        user_id: i64,
1249        is_access_restricted: bool,
1250    ) -> SetManagedBotAccessSettings {
1251        SetManagedBotAccessSettings::new(self.clone(), user_id, is_access_restricted)
1252    }
1253
1254    // ── Stories (business bots) ───────────────────────────────────────────────
1255
1256    /// Calls `postStory` — posts a story on behalf of a managed business account.
1257    ///
1258    /// `content` is `serde_json::Value` until `InputStoryContent` is defined in Priority 4.
1259    /// `active_period` must be one of `21600`, `43200`, `86400`, or `172800` seconds.
1260    pub fn post_story(
1261        &self,
1262        business_connection_id: impl Into<String>,
1263        content: serde_json::Value,
1264        active_period: u32,
1265    ) -> PostStory {
1266        PostStory::new(self.clone(), business_connection_id, content, active_period)
1267    }
1268    /// Calls `repostStory` — reposts a story from one managed business account to another.
1269    ///
1270    /// `active_period` must be one of `21600`, `43200`, `86400`, or `172800` seconds.
1271    pub fn repost_story(
1272        &self,
1273        business_connection_id: impl Into<String>,
1274        from_chat_id: i64,
1275        from_story_id: i64,
1276        active_period: u32,
1277    ) -> RepostStory {
1278        RepostStory::new(
1279            self.clone(),
1280            business_connection_id,
1281            from_chat_id,
1282            from_story_id,
1283            active_period,
1284        )
1285    }
1286    /// Calls `editStory` — edits a story posted by the bot on behalf of a business account.
1287    ///
1288    /// `content` is `serde_json::Value` until `InputStoryContent` is defined in Priority 4.
1289    pub fn edit_story(
1290        &self,
1291        business_connection_id: impl Into<String>,
1292        story_id: i64,
1293        content: serde_json::Value,
1294    ) -> EditStory {
1295        EditStory::new(self.clone(), business_connection_id, story_id, content)
1296    }
1297    /// Calls `deleteStory` — deletes a story posted by the bot on behalf of a business account.
1298    pub fn delete_story(
1299        &self,
1300        business_connection_id: impl Into<String>,
1301        story_id: i64,
1302    ) -> DeleteStory {
1303        DeleteStory::new(self.clone(), business_connection_id, story_id)
1304    }
1305
1306    // ── Gifts ─────────────────────────────────────────────────────────────────
1307
1308    /// Calls `getAvailableGifts` — returns all gifts the bot can send.
1309    pub fn get_available_gifts(&self) -> GetAvailableGifts {
1310        GetAvailableGifts::new(self.clone())
1311    }
1312    /// Calls `sendGift` — sends a gift to a user or channel chat.
1313    ///
1314    /// Chain `.user_id(id)` or `.chat_id(id)` to specify the recipient.
1315    pub fn send_gift(&self, gift_id: impl Into<String>) -> SendGift {
1316        SendGift::new(self.clone(), gift_id)
1317    }
1318    /// Calls `giftPremiumSubscription` — gifts a Telegram Premium subscription to a user.
1319    ///
1320    /// `month_count` must be `3`, `6`, or `12`.
1321    /// `star_count` must be `1000`, `1500`, or `2500` respectively.
1322    pub fn gift_premium_subscription(
1323        &self,
1324        user_id: i64,
1325        month_count: u32,
1326        star_count: u32,
1327    ) -> GiftPremiumSubscription {
1328        GiftPremiumSubscription::new(self.clone(), user_id, month_count, star_count)
1329    }
1330    /// Calls `getBusinessAccountGifts` — returns gifts received by a managed business account.
1331    pub fn get_business_account_gifts(
1332        &self,
1333        business_connection_id: impl Into<String>,
1334    ) -> GetBusinessAccountGifts {
1335        GetBusinessAccountGifts::new(self.clone(), business_connection_id)
1336    }
1337    /// Calls `getUserGifts` — returns gifts owned by a user.
1338    pub fn get_user_gifts(&self, user_id: i64) -> GetUserGifts {
1339        GetUserGifts::new(self.clone(), user_id)
1340    }
1341    /// Calls `getChatGifts` — returns gifts owned by a channel chat.
1342    pub fn get_chat_gifts(
1343        &self,
1344        chat_id: impl Into<rustigram_types::user::ChatId>,
1345    ) -> GetChatGifts {
1346        GetChatGifts::new(self.clone(), chat_id)
1347    }
1348    /// Calls `convertGiftToStars` — converts a business account gift to Telegram Stars.
1349    pub fn convert_gift_to_stars(
1350        &self,
1351        business_connection_id: impl Into<String>,
1352        owned_gift_id: impl Into<String>,
1353    ) -> ConvertGiftToStars {
1354        ConvertGiftToStars::new(self.clone(), business_connection_id, owned_gift_id)
1355    }
1356    /// Calls `upgradeGift` — upgrades a regular gift to a unique gift.
1357    pub fn upgrade_gift(
1358        &self,
1359        business_connection_id: impl Into<String>,
1360        owned_gift_id: impl Into<String>,
1361    ) -> UpgradeGift {
1362        UpgradeGift::new(self.clone(), business_connection_id, owned_gift_id)
1363    }
1364    /// Calls `transferGift` — transfers a unique gift to another user.
1365    pub fn transfer_gift(
1366        &self,
1367        business_connection_id: impl Into<String>,
1368        owned_gift_id: impl Into<String>,
1369        new_owner_chat_id: i64,
1370    ) -> TransferGift {
1371        TransferGift::new(
1372            self.clone(),
1373            business_connection_id,
1374            owned_gift_id,
1375            new_owner_chat_id,
1376        )
1377    }
1378
1379    // ── Reactions ─────────────────────────────────────────────────────────────
1380
1381    /// Calls `setMessageReaction` — sets a reaction on a message.
1382    pub fn set_message_reaction(
1383        &self,
1384        chat_id: impl Into<rustigram_types::user::ChatId>,
1385        message_id: i64,
1386    ) -> SetMessageReaction {
1387        SetMessageReaction::new(self.clone(), chat_id, message_id)
1388    }
1389    /// Calls `deleteMessageReaction` — removes a specific reaction from a message (Bot API 9.7).
1390    pub fn delete_message_reaction(
1391        &self,
1392        chat_id: impl Into<rustigram_types::user::ChatId>,
1393        message_id: i64,
1394    ) -> DeleteMessageReaction {
1395        DeleteMessageReaction::new(self.clone(), chat_id, message_id)
1396    }
1397    /// Calls `deleteAllMessageReactions` — removes all recent reactions by a given user or chat (Bot API 9.7).
1398    pub fn delete_all_message_reactions(
1399        &self,
1400        chat_id: impl Into<rustigram_types::user::ChatId>,
1401    ) -> DeleteAllMessageReactions {
1402        DeleteAllMessageReactions::new(self.clone(), chat_id)
1403    }
1404
1405    // ── Inline mode ───────────────────────────────────────────────────────────
1406
1407    /// Calls `answerInlineQuery` — sends up to 50 results for an inline query.
1408    pub fn answer_inline_query(
1409        &self,
1410        inline_query_id: impl Into<String>,
1411        results: Vec<rustigram_types::inline::InlineQueryResult>,
1412    ) -> AnswerInlineQuery {
1413        AnswerInlineQuery::new(self.clone(), inline_query_id, results)
1414    }
1415    /// Calls `answerWebAppQuery` — sets the result of a Web App interaction and sends it to the chat.
1416    pub fn answer_web_app_query(
1417        &self,
1418        web_app_query_id: impl Into<String>,
1419        result: rustigram_types::inline::InlineQueryResult,
1420    ) -> AnswerWebAppQuery {
1421        AnswerWebAppQuery::new(self.clone(), web_app_query_id, result)
1422    }
1423    /// Calls `answerGuestQuery` — replies to a received guest message (Bot API 9.7).
1424    pub fn answer_guest_query(
1425        &self,
1426        guest_query_id: impl Into<String>,
1427        result: rustigram_types::inline::InlineQueryResult,
1428    ) -> AnswerGuestQuery {
1429        AnswerGuestQuery::new(self.clone(), guest_query_id, result)
1430    }
1431    /// Calls `savePreparedInlineMessage` — stores a message sendable by a Mini App user.
1432    pub fn save_prepared_inline_message(
1433        &self,
1434        user_id: i64,
1435        result: rustigram_types::inline::InlineQueryResult,
1436    ) -> SavePreparedInlineMessage {
1437        SavePreparedInlineMessage::new(self.clone(), user_id, result)
1438    }
1439
1440    // ── Mini App ──────────────────────────────────────────────────────────────
1441
1442    /// Calls `savePreparedKeyboardButton` — stores a keyboard button for use in a Mini App (Bot API 9.6).
1443    ///
1444    /// The button must be of type `request_users`, `request_chat`, or `request_managed_bot`.
1445    pub fn save_prepared_keyboard_button(
1446        &self,
1447        user_id: i64,
1448        button: rustigram_types::keyboard::KeyboardButton,
1449    ) -> SavePreparedKeyboardButton {
1450        SavePreparedKeyboardButton::new(self.clone(), user_id, button)
1451    }
1452    /// Calls `setUserEmojiStatus` — changes a user's emoji status via a Mini App.
1453    pub fn set_user_emoji_status(&self, user_id: i64) -> SetUserEmojiStatus {
1454        SetUserEmojiStatus::new(self.clone(), user_id)
1455    }
1456
1457    // ── Passport ──────────────────────────────────────────────────────────────
1458
1459    /// Calls `setPassportDataErrors` — reports errors in Telegram Passport elements.
1460    ///
1461    /// Each error is a `serde_json::Value` — serialise from
1462    /// `rustigram_types::passport::PassportElementError` variants.
1463    pub fn set_passport_data_errors(
1464        &self,
1465        user_id: i64,
1466        errors: Vec<serde_json::Value>,
1467    ) -> SetPassportDataErrors {
1468        SetPassportDataErrors::new(self.clone(), user_id, errors)
1469    }
1470
1471    // ── Games ─────────────────────────────────────────────────────────────────
1472
1473    /// Calls `setGameScore` — sets a user's score in a game.
1474    ///
1475    /// Chain `.chat_message(chat_id, message_id)` or `.inline_message_id(id)` to target the message.
1476    pub fn set_game_score(&self, user_id: i64, score: u32) -> SetGameScore {
1477        SetGameScore::new(self.clone(), user_id, score)
1478    }
1479    /// Calls `getGameHighScores` — returns high scores for a game.
1480    ///
1481    /// Chain `.chat_message(chat_id, message_id)` or `.inline_message_id(id)` to target the message.
1482    pub fn get_game_high_scores(&self, user_id: i64) -> GetGameHighScores {
1483        GetGameHighScores::new(self.clone(), user_id)
1484    }
1485
1486    // ── Payments ──────────────────────────────────────────────────────────────
1487
1488    /// Calls `sendInvoice` — sends a payment invoice.
1489    pub fn send_invoice(
1490        &self,
1491        chat_id: impl Into<rustigram_types::user::ChatId>,
1492        title: impl Into<String>,
1493        description: impl Into<String>,
1494        payload: impl Into<String>,
1495        currency: impl Into<String>,
1496        prices: Vec<rustigram_types::payments::LabeledPrice>,
1497    ) -> SendInvoice {
1498        SendInvoice::new(
1499            self.clone(),
1500            chat_id,
1501            title,
1502            description,
1503            payload,
1504            currency,
1505            prices,
1506        )
1507    }
1508    /// Calls `createInvoiceLink` — creates a shareable payment link.
1509    pub fn create_invoice_link(
1510        &self,
1511        title: impl Into<String>,
1512        description: impl Into<String>,
1513        payload: impl Into<String>,
1514        currency: impl Into<String>,
1515        prices: Vec<rustigram_types::payments::LabeledPrice>,
1516    ) -> CreateInvoiceLink {
1517        CreateInvoiceLink::new(self.clone(), title, description, payload, currency, prices)
1518    }
1519    /// Calls `answerShippingQuery` — responds to a shipping query from a user.
1520    ///
1521    /// Pass `ok = true` and provide `shipping_options`; or `ok = false` with an `error_message`.
1522    pub fn answer_shipping_query(
1523        &self,
1524        shipping_query_id: impl Into<String>,
1525        ok: bool,
1526    ) -> AnswerShippingQuery {
1527        AnswerShippingQuery::new(self.clone(), shipping_query_id, ok)
1528    }
1529    /// Calls `answerPreCheckoutQuery` — confirms or rejects a pre-checkout query.
1530    ///
1531    /// Must be called within **10 seconds** of receiving the query.
1532    pub fn answer_pre_checkout_query(
1533        &self,
1534        pre_checkout_query_id: impl Into<String>,
1535        ok: bool,
1536    ) -> AnswerPreCheckoutQuery {
1537        AnswerPreCheckoutQuery::new(self.clone(), pre_checkout_query_id, ok)
1538    }
1539    /// Calls `refundStarPayment` — refunds a successful Telegram Stars payment.
1540    pub fn refund_star_payment(
1541        &self,
1542        user_id: i64,
1543        telegram_payment_charge_id: impl Into<String>,
1544    ) -> RefundStarPayment {
1545        RefundStarPayment::new(self.clone(), user_id, telegram_payment_charge_id)
1546    }
1547    /// Calls `editUserStarSubscription` — cancels or re-enables a Stars subscription.
1548    pub fn edit_user_star_subscription(
1549        &self,
1550        user_id: i64,
1551        telegram_payment_charge_id: impl Into<String>,
1552        is_canceled: bool,
1553    ) -> EditUserStarSubscription {
1554        EditUserStarSubscription::new(
1555            self.clone(),
1556            user_id,
1557            telegram_payment_charge_id,
1558            is_canceled,
1559        )
1560    }
1561    /// Calls `getMyStarBalance` — returns the bot's Telegram Star balance.
1562    pub fn get_my_star_balance(&self) -> GetMyStarBalance {
1563        GetMyStarBalance::new(self.clone())
1564    }
1565    /// Calls `getStarTransactions` — returns the bot's Star transaction history.
1566    pub fn get_star_transactions(&self) -> GetStarTransactions {
1567        GetStarTransactions::new(self.clone())
1568    }
1569
1570    // ── Stickers ──────────────────────────────────────────────────────────────
1571
1572    /// Calls `getStickerSet` — returns a sticker set by name.
1573    pub fn get_sticker_set(&self, name: impl Into<String>) -> GetStickerSet {
1574        GetStickerSet::new(self.clone(), name)
1575    }
1576    /// Calls `getCustomEmojiStickers` — returns stickers for the given custom emoji IDs.
1577    pub fn get_custom_emoji_stickers(&self, ids: Vec<impl Into<String>>) -> GetCustomEmojiStickers {
1578        GetCustomEmojiStickers::new(self.clone(), ids)
1579    }
1580    /// Calls `uploadStickerFile` — uploads a sticker file for later use in a set.
1581    pub fn upload_sticker_file(
1582        &self,
1583        user_id: i64,
1584        sticker: rustigram_types::file::InputFile,
1585        format: rustigram_types::sticker::StickerFormat,
1586    ) -> UploadStickerFile {
1587        UploadStickerFile::new(self.clone(), user_id, sticker, format)
1588    }
1589    /// Calls `createNewStickerSet` — creates a new sticker set owned by a user.
1590    pub fn create_new_sticker_set(
1591        &self,
1592        user_id: i64,
1593        name: impl Into<String>,
1594        title: impl Into<String>,
1595        stickers: Vec<rustigram_types::sticker::InputSticker>,
1596    ) -> CreateNewStickerSet {
1597        CreateNewStickerSet::new(self.clone(), user_id, name, title, stickers)
1598    }
1599    /// Calls `addStickerToSet` — adds a new sticker to an existing set.
1600    pub fn add_sticker_to_set(
1601        &self,
1602        user_id: i64,
1603        name: impl Into<String>,
1604        sticker: rustigram_types::sticker::InputSticker,
1605    ) -> AddStickerToSet {
1606        AddStickerToSet::new(self.clone(), user_id, name, sticker)
1607    }
1608    /// Calls `setStickerPositionInSet` — moves a sticker to a new position in its set.
1609    pub fn set_sticker_position_in_set(
1610        &self,
1611        sticker: impl Into<String>,
1612        position: u32,
1613    ) -> SetStickerPositionInSet {
1614        SetStickerPositionInSet::new(self.clone(), sticker, position)
1615    }
1616    /// Calls `deleteStickerFromSet` — removes a sticker from its set.
1617    pub fn delete_sticker_from_set(&self, sticker: impl Into<String>) -> DeleteStickerFromSet {
1618        DeleteStickerFromSet::new(self.clone(), sticker)
1619    }
1620    /// Calls `setStickerEmojiList` — updates the emoji list for a sticker.
1621    pub fn set_sticker_emoji_list(
1622        &self,
1623        sticker: impl Into<String>,
1624        emoji_list: Vec<impl Into<String>>,
1625    ) -> SetStickerEmojiList {
1626        SetStickerEmojiList::new(self.clone(), sticker, emoji_list)
1627    }
1628    /// Calls `setStickerKeywords` — updates the search keywords for a sticker.
1629    pub fn set_sticker_keywords(&self, sticker: impl Into<String>) -> SetStickerKeywords {
1630        SetStickerKeywords::new(self.clone(), sticker)
1631    }
1632    /// Calls `setStickerMaskPosition` — updates the mask position for a mask sticker.
1633    pub fn set_sticker_mask_position(&self, sticker: impl Into<String>) -> SetStickerMaskPosition {
1634        SetStickerMaskPosition::new(self.clone(), sticker)
1635    }
1636    /// Calls `setStickerSetTitle` — renames a sticker set.
1637    pub fn set_sticker_set_title(
1638        &self,
1639        name: impl Into<String>,
1640        title: impl Into<String>,
1641    ) -> SetStickerSetTitle {
1642        SetStickerSetTitle::new(self.clone(), name, title)
1643    }
1644    /// Calls `deleteStickerSet` — deletes a sticker set created by the bot.
1645    pub fn delete_sticker_set(&self, name: impl Into<String>) -> DeleteStickerSet {
1646        DeleteStickerSet::new(self.clone(), name)
1647    }
1648    /// Calls `replaceStickerInSet` — replaces an existing sticker in a set with a new one.
1649    pub fn replace_sticker_in_set(
1650        &self,
1651        user_id: i64,
1652        name: impl Into<String>,
1653        old_sticker: impl Into<String>,
1654        sticker: rustigram_types::sticker::InputSticker,
1655    ) -> ReplaceStickerInSet {
1656        ReplaceStickerInSet::new(self.clone(), user_id, name, old_sticker, sticker)
1657    }
1658    /// Calls `setStickerSetThumbnail` — sets the thumbnail of a regular or mask sticker set.
1659    ///
1660    /// `format` must be `"static"`, `"animated"`, or `"video"`.
1661    /// Chain `.thumbnail(file)` to set the thumbnail; omit to drop it.
1662    pub fn set_sticker_set_thumbnail(
1663        &self,
1664        name: impl Into<String>,
1665        user_id: i64,
1666        format: impl Into<String>,
1667    ) -> SetStickerSetThumbnail {
1668        SetStickerSetThumbnail::new(self.clone(), name, user_id, format)
1669    }
1670    /// Calls `setCustomEmojiStickerSetThumbnail` — sets the thumbnail of a custom emoji sticker set.
1671    ///
1672    /// Chain `.custom_emoji_id(id)` to set the thumbnail emoji; omit to use the first sticker.
1673    pub fn set_custom_emoji_sticker_set_thumbnail(
1674        &self,
1675        name: impl Into<String>,
1676    ) -> SetCustomEmojiStickerSetThumbnail {
1677        SetCustomEmojiStickerSetThumbnail::new(self.clone(), name)
1678    }
1679    /// Calls `getForumTopicIconStickers` — returns all available forum topic icon stickers.
1680    pub fn get_forum_topic_icon_stickers(&self) -> GetForumTopicIconStickers {
1681        GetForumTopicIconStickers::new(self.clone())
1682    }
1683
1684    // ── Forum topics ──────────────────────────────────────────────────────────
1685
1686    /// Calls `createForumTopic` — creates a new topic in a forum supergroup.
1687    pub fn create_forum_topic(
1688        &self,
1689        chat_id: impl Into<rustigram_types::user::ChatId>,
1690        name: impl Into<String>,
1691    ) -> CreateForumTopic {
1692        CreateForumTopic::new(self.clone(), chat_id, name)
1693    }
1694    /// Calls `editForumTopic` — edits the name or icon of a forum topic.
1695    pub fn edit_forum_topic(
1696        &self,
1697        chat_id: impl Into<rustigram_types::user::ChatId>,
1698        thread_id: i64,
1699    ) -> EditForumTopic {
1700        EditForumTopic::new(self.clone(), chat_id, thread_id)
1701    }
1702    /// Calls `closeForumTopic` — closes an open forum topic.
1703    pub fn close_forum_topic(
1704        &self,
1705        chat_id: impl Into<rustigram_types::user::ChatId>,
1706        thread_id: i64,
1707    ) -> CloseForumTopic {
1708        CloseForumTopic::new(self.clone(), chat_id, thread_id)
1709    }
1710    /// Calls `reopenForumTopic` — reopens a closed forum topic.
1711    pub fn reopen_forum_topic(
1712        &self,
1713        chat_id: impl Into<rustigram_types::user::ChatId>,
1714        thread_id: i64,
1715    ) -> ReopenForumTopic {
1716        ReopenForumTopic::new(self.clone(), chat_id, thread_id)
1717    }
1718    /// Calls `deleteForumTopic` — deletes a forum topic and all its messages.
1719    pub fn delete_forum_topic(
1720        &self,
1721        chat_id: impl Into<rustigram_types::user::ChatId>,
1722        thread_id: i64,
1723    ) -> DeleteForumTopic {
1724        DeleteForumTopic::new(self.clone(), chat_id, thread_id)
1725    }
1726    /// Calls `editGeneralForumTopic` — renames the General topic.
1727    pub fn edit_general_forum_topic(
1728        &self,
1729        chat_id: impl Into<rustigram_types::user::ChatId>,
1730        name: impl Into<String>,
1731    ) -> EditGeneralForumTopic {
1732        EditGeneralForumTopic::new(self.clone(), chat_id, name)
1733    }
1734    /// Calls `closeGeneralForumTopic` — closes the General topic.
1735    pub fn close_general_forum_topic(
1736        &self,
1737        chat_id: impl Into<rustigram_types::user::ChatId>,
1738    ) -> CloseGeneralForumTopic {
1739        CloseGeneralForumTopic::new(self.clone(), chat_id)
1740    }
1741    /// Calls `reopenGeneralForumTopic` — reopens the General topic.
1742    pub fn reopen_general_forum_topic(
1743        &self,
1744        chat_id: impl Into<rustigram_types::user::ChatId>,
1745    ) -> ReopenGeneralForumTopic {
1746        ReopenGeneralForumTopic::new(self.clone(), chat_id)
1747    }
1748    /// Calls `hideGeneralForumTopic` — hides the General topic from the topic list.
1749    pub fn hide_general_forum_topic(
1750        &self,
1751        chat_id: impl Into<rustigram_types::user::ChatId>,
1752    ) -> HideGeneralForumTopic {
1753        HideGeneralForumTopic::new(self.clone(), chat_id)
1754    }
1755    /// Calls `unhideGeneralForumTopic` — makes the General topic visible again.
1756    pub fn unhide_general_forum_topic(
1757        &self,
1758        chat_id: impl Into<rustigram_types::user::ChatId>,
1759    ) -> UnhideGeneralForumTopic {
1760        UnhideGeneralForumTopic::new(self.clone(), chat_id)
1761    }
1762    /// Calls `unpinAllGeneralForumTopicMessages` — clears all pinned messages in the General forum topic.
1763    pub fn unpin_all_general_forum_topic_messages(
1764        &self,
1765        chat_id: impl Into<rustigram_types::user::ChatId>,
1766    ) -> UnpinAllGeneralForumTopicMessages {
1767        UnpinAllGeneralForumTopicMessages::new(self.clone(), chat_id)
1768    }
1769
1770    // ── Verification ──────────────────────────────────────────────────────────
1771
1772    /// Calls `verifyUser` — verifies a user on behalf of the organisation.
1773    pub fn verify_user(&self, user_id: i64) -> VerifyUser {
1774        VerifyUser::new(self.clone(), user_id)
1775    }
1776    /// Calls `verifyChat` — verifies a chat on behalf of the organisation.
1777    pub fn verify_chat(&self, chat_id: impl Into<rustigram_types::user::ChatId>) -> VerifyChat {
1778        VerifyChat::new(self.clone(), chat_id)
1779    }
1780    /// Calls `removeUserVerification` — removes verification from a user.
1781    pub fn remove_user_verification(&self, user_id: i64) -> RemoveUserVerification {
1782        RemoveUserVerification::new(self.clone(), user_id)
1783    }
1784    /// Calls `removeChatVerification` — removes verification from a chat.
1785    pub fn remove_chat_verification(
1786        &self,
1787        chat_id: impl Into<rustigram_types::user::ChatId>,
1788    ) -> RemoveChatVerification {
1789        RemoveChatVerification::new(self.clone(), chat_id)
1790    }
1791
1792    // ── Business account ──────────────────────────────────────────────────────
1793
1794    /// Calls `getBusinessConnection` — returns business connection information.
1795    pub fn get_business_connection(&self, id: impl Into<String>) -> GetBusinessConnection {
1796        GetBusinessConnection::new(self.clone(), id)
1797    }
1798    /// Calls `readBusinessMessage` — marks a business account message as read.
1799    pub fn read_business_message(
1800        &self,
1801        business_connection_id: impl Into<String>,
1802        chat_id: impl Into<rustigram_types::user::ChatId>,
1803        message_id: i64,
1804    ) -> ReadBusinessMessage {
1805        ReadBusinessMessage::new(self.clone(), business_connection_id, chat_id, message_id)
1806    }
1807    /// Calls `deleteBusinessMessages` — deletes messages from a business account.
1808    pub fn delete_business_messages(
1809        &self,
1810        business_connection_id: impl Into<String>,
1811        message_ids: Vec<i64>,
1812    ) -> DeleteBusinessMessages {
1813        DeleteBusinessMessages::new(self.clone(), business_connection_id, message_ids)
1814    }
1815    /// Calls `setBusinessAccountName` — sets the name of a managed business account.
1816    pub fn set_business_account_name(
1817        &self,
1818        business_connection_id: impl Into<String>,
1819        first_name: impl Into<String>,
1820        last_name: Option<String>,
1821    ) -> SetBusinessAccountName {
1822        SetBusinessAccountName::new(
1823            self.clone(),
1824            business_connection_id,
1825            first_name.into(),
1826            last_name,
1827        )
1828    }
1829    /// Calls `setBusinessAccountUsername` — sets the username of a managed business account.
1830    pub fn set_business_account_username(
1831        &self,
1832        business_connection_id: impl Into<String>,
1833        username: Option<String>,
1834    ) -> SetBusinessAccountUsername {
1835        SetBusinessAccountUsername::new(self.clone(), business_connection_id, username)
1836    }
1837    /// Calls `setBusinessAccountBio` — sets the bio of a managed business account.
1838    pub fn set_business_account_bio(
1839        &self,
1840        business_connection_id: impl Into<String>,
1841        bio: Option<String>,
1842    ) -> SetBusinessAccountBio {
1843        SetBusinessAccountBio::new(self.clone(), business_connection_id, bio)
1844    }
1845    /// Calls `getBusinessAccountStarBalance` — returns a business account's Star balance.
1846    pub fn get_business_account_star_balance(
1847        &self,
1848        business_connection_id: impl Into<String>,
1849    ) -> GetBusinessAccountStarBalance {
1850        GetBusinessAccountStarBalance::new(self.clone(), business_connection_id)
1851    }
1852    /// Calls `transferBusinessAccountStars` — transfers Stars from a business account to the bot.
1853    pub fn transfer_business_account_stars(
1854        &self,
1855        business_connection_id: impl Into<String>,
1856        star_count: u64,
1857    ) -> TransferBusinessAccountStars {
1858        TransferBusinessAccountStars::new(self.clone(), business_connection_id, star_count)
1859    }
1860    /// Calls `unpinAllForumTopicMessages` — clears all pinned messages in a forum topic.
1861    pub fn unpin_all_forum_topic_messages(
1862        &self,
1863        chat_id: impl Into<rustigram_types::user::ChatId>,
1864        thread_id: i64,
1865    ) -> UnpinAllForumTopicMessages {
1866        UnpinAllForumTopicMessages::new(self.clone(), chat_id, thread_id)
1867    }
1868
1869    /// Calls `setBusinessAccountProfilePhoto` — sets the profile photo of a managed business account.
1870    ///
1871    /// Pass `photo` as `serde_json::to_value(&input_profile_photo)`.
1872    pub fn set_business_account_profile_photo(
1873        &self,
1874        business_connection_id: impl Into<String>,
1875        photo: serde_json::Value,
1876    ) -> SetBusinessAccountProfilePhoto {
1877        SetBusinessAccountProfilePhoto::new(self.clone(), business_connection_id, photo)
1878    }
1879
1880    /// Calls `removeBusinessAccountProfilePhoto` — removes the profile photo of a managed business account.
1881    pub fn remove_business_account_profile_photo(
1882        &self,
1883        business_connection_id: impl Into<String>,
1884    ) -> RemoveBusinessAccountProfilePhoto {
1885        RemoveBusinessAccountProfilePhoto::new(self.clone(), business_connection_id)
1886    }
1887
1888    /// Calls `setBusinessAccountGiftSettings` — changes gift privacy settings for a managed business account.
1889    pub fn set_business_account_gift_settings(
1890        &self,
1891        business_connection_id: impl Into<String>,
1892        show_gift_button: bool,
1893        accepted_gift_types: rustigram_types::payments::AcceptedGiftTypes,
1894    ) -> SetBusinessAccountGiftSettings {
1895        SetBusinessAccountGiftSettings::new(
1896            self.clone(),
1897            business_connection_id,
1898            show_gift_button,
1899            accepted_gift_types,
1900        )
1901    }
1902}
1903
1904// ─── Helpers ──────────────────────────────────────────────────────────────────
1905
1906#[allow(dead_code)]
1907/// Converts an `InputFile::Bytes` into a multipart `Part` for file uploads.
1908pub(crate) fn input_file_to_part(file: rustigram_types::file::InputFile) -> Option<(String, Part)> {
1909    use rustigram_types::file::InputFile;
1910    match file {
1911        InputFile::Bytes {
1912            filename,
1913            data,
1914            mime_type,
1915        } => {
1916            let part = Part::bytes(data)
1917                .file_name(filename.clone())
1918                .mime_str(&mime_type)
1919                .ok()?;
1920            Some((filename, part))
1921        }
1922        _ => None,
1923    }
1924}
1925
1926fn validate_token(token: &str) -> Result<()> {
1927    let colon = token.find(':').ok_or(Error::InvalidToken)?;
1928    let id_part = &token[..colon];
1929    if id_part.is_empty() || !id_part.chars().all(|c| c.is_ascii_digit()) {
1930        return Err(Error::InvalidToken);
1931    }
1932    if token[colon + 1..].is_empty() {
1933        return Err(Error::InvalidToken);
1934    }
1935    Ok(())
1936}