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 `stopPoll` — stops an open poll.
693    pub fn stop_poll(
694        &self,
695        chat_id: impl Into<rustigram_types::user::ChatId>,
696        message_id: i64,
697    ) -> StopPoll {
698        StopPoll::new(self.clone(), chat_id, message_id)
699    }
700    /// Calls `answerCallbackQuery` — acknowledges a callback button press.
701    pub fn answer_callback_query(
702        &self,
703        callback_query_id: impl Into<String>,
704    ) -> AnswerCallbackQuery {
705        AnswerCallbackQuery::new(self.clone(), callback_query_id)
706    }
707
708    // ── Editing ───────────────────────────────────────────────────────────────
709
710    /// Calls `editMessageText` — edits the text of a sent message.
711    pub fn edit_message_text(
712        &self,
713        chat_id: impl Into<rustigram_types::user::ChatId>,
714        message_id: i64,
715        text: impl Into<String>,
716    ) -> EditMessageText {
717        EditMessageText::in_chat(self.clone(), chat_id, message_id, text)
718    }
719    /// Calls `editMessageText` for an inline message sent via inline mode.
720    pub fn edit_inline_message_text(
721        &self,
722        inline_message_id: impl Into<String>,
723        text: impl Into<String>,
724    ) -> EditMessageText {
725        EditMessageText::inline(self.clone(), inline_message_id, text)
726    }
727    /// Calls `editMessageText` to replace a chat message with rich formatted content.
728    pub fn edit_message_rich_text(
729        &self,
730        chat_id: impl Into<rustigram_types::user::ChatId>,
731        message_id: i64,
732        rich_message: rustigram_types::rich_message::InputRichMessage,
733    ) -> EditMessageText {
734        EditMessageText::in_chat_rich(self.clone(), chat_id, message_id, rich_message)
735    }
736    /// Calls `editMessageText` to replace an inline message with rich formatted content.
737    pub fn edit_inline_message_rich_text(
738        &self,
739        inline_message_id: impl Into<String>,
740        rich_message: rustigram_types::rich_message::InputRichMessage,
741    ) -> EditMessageText {
742        EditMessageText::inline_rich(self.clone(), inline_message_id, rich_message)
743    }
744    /// Calls `editMessageCaption` — edits the caption of a media message.
745    pub fn edit_message_caption(
746        &self,
747        chat_id: impl Into<rustigram_types::user::ChatId>,
748        message_id: i64,
749    ) -> EditMessageCaption {
750        EditMessageCaption::in_chat(self.clone(), chat_id, message_id)
751    }
752    /// Calls `editMessageCaption` for an inline message sent via inline mode.
753    pub fn edit_inline_message_caption(
754        &self,
755        inline_message_id: impl Into<String>,
756    ) -> EditMessageCaption {
757        EditMessageCaption::inline(self.clone(), inline_message_id)
758    }
759    /// Calls `editMessageMedia` — replaces the media content of a message.
760    ///
761    /// The `media` parameter accepts `serde_json::Value` until `InputMedia` is
762    /// defined in Priority 4.
763    pub fn edit_message_media(
764        &self,
765        chat_id: impl Into<rustigram_types::user::ChatId>,
766        message_id: i64,
767        media: serde_json::Value,
768    ) -> EditMessageMedia {
769        EditMessageMedia::in_chat(self.clone(), chat_id, message_id, media)
770    }
771    /// Calls `editMessageMedia` for an inline message sent via inline mode.
772    pub fn edit_inline_message_media(
773        &self,
774        inline_message_id: impl Into<String>,
775        media: serde_json::Value,
776    ) -> EditMessageMedia {
777        EditMessageMedia::inline(self.clone(), inline_message_id, media)
778    }
779    /// Calls `editMessageReplyMarkup` — replaces the inline keyboard of a message.
780    pub fn edit_message_reply_markup(
781        &self,
782        chat_id: impl Into<rustigram_types::user::ChatId>,
783        message_id: i64,
784    ) -> EditMessageReplyMarkup {
785        EditMessageReplyMarkup::in_chat(self.clone(), chat_id, message_id)
786    }
787    /// Calls `editMessageReplyMarkup` for an inline message sent via inline mode.
788    pub fn edit_inline_message_reply_markup(
789        &self,
790        inline_message_id: impl Into<String>,
791    ) -> EditMessageReplyMarkup {
792        EditMessageReplyMarkup::inline(self.clone(), inline_message_id)
793    }
794    /// Calls `editMessageChecklist` — edits a checklist on behalf of a business account.
795    pub fn edit_message_checklist(
796        &self,
797        business_connection_id: impl Into<String>,
798        chat_id: i64,
799        message_id: i64,
800        checklist: rustigram_types::checklist::InputChecklist,
801    ) -> EditMessageChecklist {
802        EditMessageChecklist::new(
803            self.clone(),
804            business_connection_id,
805            chat_id,
806            message_id,
807            checklist,
808        )
809    }
810    /// Calls `approveSuggestedPost` — approves a suggested post in a direct messages chat.
811    pub fn approve_suggested_post(&self, chat_id: i64, message_id: i64) -> ApproveSuggestedPost {
812        ApproveSuggestedPost::new(self.clone(), chat_id, message_id)
813    }
814    /// Calls `declineSuggestedPost` — declines a suggested post in a direct messages chat.
815    pub fn decline_suggested_post(&self, chat_id: i64, message_id: i64) -> DeclineSuggestedPost {
816        DeclineSuggestedPost::new(self.clone(), chat_id, message_id)
817    }
818    /// Calls `editMessageLiveLocation` — updates the position of a live location.
819    pub fn edit_message_live_location(
820        &self,
821        chat_id: impl Into<rustigram_types::user::ChatId>,
822        message_id: i64,
823        latitude: f64,
824        longitude: f64,
825    ) -> EditMessageLiveLocation {
826        EditMessageLiveLocation::in_chat(self.clone(), chat_id, message_id, latitude, longitude)
827    }
828    /// Calls `editMessageLiveLocation` for an inline message sent via inline mode.
829    pub fn edit_inline_message_live_location(
830        &self,
831        inline_message_id: impl Into<String>,
832        latitude: f64,
833        longitude: f64,
834    ) -> EditMessageLiveLocation {
835        EditMessageLiveLocation::inline(self.clone(), inline_message_id, latitude, longitude)
836    }
837    /// Calls `stopMessageLiveLocation` — stops a live location from updating.
838    pub fn stop_message_live_location(
839        &self,
840        chat_id: impl Into<rustigram_types::user::ChatId>,
841        message_id: i64,
842    ) -> StopMessageLiveLocation {
843        StopMessageLiveLocation::in_chat(self.clone(), chat_id, message_id)
844    }
845    /// Calls `stopMessageLiveLocation` for an inline message sent via inline mode.
846    pub fn stop_inline_message_live_location(
847        &self,
848        inline_message_id: impl Into<String>,
849    ) -> StopMessageLiveLocation {
850        StopMessageLiveLocation::inline(self.clone(), inline_message_id)
851    }
852
853    // ── Chat management ───────────────────────────────────────────────────────
854
855    /// Calls `banChatMember` — bans a user from a chat.
856    pub fn ban_chat_member(
857        &self,
858        chat_id: impl Into<rustigram_types::user::ChatId>,
859        user_id: i64,
860    ) -> BanChatMember {
861        BanChatMember::new(self.clone(), chat_id, user_id)
862    }
863    /// Calls `unbanChatMember` — lifts a ban from a user.
864    pub fn unban_chat_member(
865        &self,
866        chat_id: impl Into<rustigram_types::user::ChatId>,
867        user_id: i64,
868    ) -> UnbanChatMember {
869        UnbanChatMember::new(self.clone(), chat_id, user_id)
870    }
871    /// Calls `restrictChatMember` — restricts what a user can do in a chat.
872    pub fn restrict_chat_member(
873        &self,
874        chat_id: impl Into<rustigram_types::user::ChatId>,
875        user_id: i64,
876        permissions: rustigram_types::chat::ChatPermissions,
877    ) -> RestrictChatMember {
878        RestrictChatMember::new(self.clone(), chat_id, user_id, permissions)
879    }
880    /// Calls `promoteChatMember` — grants or revokes admin privileges.
881    pub fn promote_chat_member(
882        &self,
883        chat_id: impl Into<rustigram_types::user::ChatId>,
884        user_id: i64,
885    ) -> PromoteChatMember {
886        PromoteChatMember::new(self.clone(), chat_id, user_id)
887    }
888    /// Calls `setChatAdministratorCustomTitle` — sets a custom title for an admin.
889    pub fn set_chat_administrator_custom_title(
890        &self,
891        chat_id: impl Into<rustigram_types::user::ChatId>,
892        user_id: i64,
893        custom_title: impl Into<String>,
894    ) -> SetChatAdministratorCustomTitle {
895        SetChatAdministratorCustomTitle::new(self.clone(), chat_id, user_id, custom_title)
896    }
897    /// Calls `setChatMemberTag` — sets a tag for a regular member (Bot API 9.5).
898    pub fn set_chat_member_tag(
899        &self,
900        chat_id: impl Into<rustigram_types::user::ChatId>,
901        user_id: i64,
902    ) -> SetChatMemberTag {
903        SetChatMemberTag::new(self.clone(), chat_id, user_id)
904    }
905    /// Calls `setChatPermissions` — sets default chat permissions for all members.
906    pub fn set_chat_permissions(
907        &self,
908        chat_id: impl Into<rustigram_types::user::ChatId>,
909        permissions: rustigram_types::chat::ChatPermissions,
910    ) -> SetChatPermissions {
911        SetChatPermissions::new(self.clone(), chat_id, permissions)
912    }
913    /// Calls `exportChatInviteLink` — generates a new primary invite link, revoking the old one.
914    pub fn export_chat_invite_link(
915        &self,
916        chat_id: impl Into<rustigram_types::user::ChatId>,
917    ) -> ExportChatInviteLink {
918        ExportChatInviteLink::new(self.clone(), chat_id)
919    }
920    /// Calls `createChatInviteLink` — generates a new additional invite link.
921    pub fn create_chat_invite_link(
922        &self,
923        chat_id: impl Into<rustigram_types::user::ChatId>,
924    ) -> CreateChatInviteLink {
925        CreateChatInviteLink::new(self.clone(), chat_id)
926    }
927    /// Calls `editChatInviteLink` — edits a non-primary invite link created by the bot.
928    pub fn edit_chat_invite_link(
929        &self,
930        chat_id: impl Into<rustigram_types::user::ChatId>,
931        invite_link: impl Into<String>,
932    ) -> EditChatInviteLink {
933        EditChatInviteLink::new(self.clone(), chat_id, invite_link)
934    }
935    /// Calls `revokeChatInviteLink` — revokes an invite link created by the bot.
936    pub fn revoke_chat_invite_link(
937        &self,
938        chat_id: impl Into<rustigram_types::user::ChatId>,
939        invite_link: impl Into<String>,
940    ) -> RevokeChatInviteLink {
941        RevokeChatInviteLink::new(self.clone(), chat_id, invite_link)
942    }
943    /// Calls `createChatSubscriptionInviteLink` — creates a subscription invite link for a channel.
944    pub fn create_chat_subscription_invite_link(
945        &self,
946        chat_id: impl Into<rustigram_types::user::ChatId>,
947        subscription_period: u32,
948        subscription_price: u32,
949    ) -> CreateChatSubscriptionInviteLink {
950        CreateChatSubscriptionInviteLink::new(
951            self.clone(),
952            chat_id,
953            subscription_period,
954            subscription_price,
955        )
956    }
957    /// Calls `editChatSubscriptionInviteLink` — edits a subscription invite link.
958    pub fn edit_chat_subscription_invite_link(
959        &self,
960        chat_id: impl Into<rustigram_types::user::ChatId>,
961        invite_link: impl Into<String>,
962    ) -> EditChatSubscriptionInviteLink {
963        EditChatSubscriptionInviteLink::new(self.clone(), chat_id, invite_link)
964    }
965    /// Calls `approveChatJoinRequest` — approves a pending join request.
966    pub fn approve_chat_join_request(
967        &self,
968        chat_id: impl Into<rustigram_types::user::ChatId>,
969        user_id: i64,
970    ) -> ApproveChatJoinRequest {
971        ApproveChatJoinRequest::new(self.clone(), chat_id, user_id)
972    }
973    /// Calls `declineChatJoinRequest` — declines a pending join request.
974    pub fn decline_chat_join_request(
975        &self,
976        chat_id: impl Into<rustigram_types::user::ChatId>,
977        user_id: i64,
978    ) -> DeclineChatJoinRequest {
979        DeclineChatJoinRequest::new(self.clone(), chat_id, user_id)
980    }
981    /// Calls `answerChatJoinRequestQuery` — processes a join request query (Bot API 10.1).
982    ///
983    /// Must be called within 10 seconds of receiving a [`ChatJoinRequest`](rustigram_types::ChatJoinRequest)
984    /// that carries a `query_id`.
985    pub fn answer_chat_join_request_query(
986        &self,
987        chat_join_request_query_id: impl Into<String>,
988        result: crate::methods::chat_management::JoinRequestResult,
989    ) -> AnswerChatJoinRequestQuery {
990        AnswerChatJoinRequestQuery::new(self.clone(), chat_join_request_query_id, result)
991    }
992    /// Calls `sendChatJoinRequestWebApp` — shows a Mini App to the user before deciding (Bot API 10.1).
993    ///
994    /// Must be called within 10 seconds of receiving a [`ChatJoinRequest`](rustigram_types::ChatJoinRequest)
995    /// that carries a `query_id`.
996    pub fn send_chat_join_request_web_app(
997        &self,
998        chat_join_request_query_id: impl Into<String>,
999        web_app_url: impl Into<String>,
1000    ) -> SendChatJoinRequestWebApp {
1001        SendChatJoinRequestWebApp::new(self.clone(), chat_join_request_query_id, web_app_url)
1002    }
1003    /// Calls `banChatSenderChat` — bans a channel chat from sending in a supergroup or channel.
1004    pub fn ban_chat_sender_chat(
1005        &self,
1006        chat_id: impl Into<rustigram_types::user::ChatId>,
1007        sender_chat_id: i64,
1008    ) -> BanChatSenderChat {
1009        BanChatSenderChat::new(self.clone(), chat_id, sender_chat_id)
1010    }
1011    /// Calls `unbanChatSenderChat` — unbans a previously banned channel chat.
1012    pub fn unban_chat_sender_chat(
1013        &self,
1014        chat_id: impl Into<rustigram_types::user::ChatId>,
1015        sender_chat_id: i64,
1016    ) -> UnbanChatSenderChat {
1017        UnbanChatSenderChat::new(self.clone(), chat_id, sender_chat_id)
1018    }
1019    /// Calls `unpinAllChatMessages` — clears all pinned messages in a chat.
1020    pub fn unpin_all_chat_messages(
1021        &self,
1022        chat_id: impl Into<rustigram_types::user::ChatId>,
1023    ) -> UnpinAllChatMessages {
1024        UnpinAllChatMessages::new(self.clone(), chat_id)
1025    }
1026    /// Calls `setChatPhoto` — sets a new profile photo for the chat.
1027    pub fn set_chat_photo(
1028        &self,
1029        chat_id: impl Into<rustigram_types::user::ChatId>,
1030        photo: rustigram_types::file::InputFile,
1031    ) -> SetChatPhoto {
1032        SetChatPhoto::new(self.clone(), chat_id, photo)
1033    }
1034    /// Calls `deleteChatPhoto` — deletes the chat photo.
1035    pub fn delete_chat_photo(
1036        &self,
1037        chat_id: impl Into<rustigram_types::user::ChatId>,
1038    ) -> DeleteChatPhoto {
1039        DeleteChatPhoto::new(self.clone(), chat_id)
1040    }
1041    /// Calls `setChatTitle` — changes the title of a chat.
1042    pub fn set_chat_title(
1043        &self,
1044        chat_id: impl Into<rustigram_types::user::ChatId>,
1045        title: impl Into<String>,
1046    ) -> SetChatTitle {
1047        SetChatTitle::new(self.clone(), chat_id, title)
1048    }
1049    /// Calls `setChatDescription` — changes the description of a group, supergroup, or channel.
1050    pub fn set_chat_description(
1051        &self,
1052        chat_id: impl Into<rustigram_types::user::ChatId>,
1053    ) -> SetChatDescription {
1054        SetChatDescription::new(self.clone(), chat_id)
1055    }
1056    /// Calls `setChatStickerSet` — sets the sticker set for a supergroup.
1057    pub fn set_chat_sticker_set(
1058        &self,
1059        chat_id: impl Into<rustigram_types::user::ChatId>,
1060        sticker_set_name: impl Into<String>,
1061    ) -> SetChatStickerSet {
1062        SetChatStickerSet::new(self.clone(), chat_id, sticker_set_name)
1063    }
1064    /// Calls `deleteChatStickerSet` — removes the sticker set from a supergroup.
1065    pub fn delete_chat_sticker_set(
1066        &self,
1067        chat_id: impl Into<rustigram_types::user::ChatId>,
1068    ) -> DeleteChatStickerSet {
1069        DeleteChatStickerSet::new(self.clone(), chat_id)
1070    }
1071    /// Calls `leaveChat` — makes the bot leave a group, supergroup, or channel.
1072    pub fn leave_chat(&self, chat_id: impl Into<rustigram_types::user::ChatId>) -> LeaveChat {
1073        LeaveChat::new(self.clone(), chat_id)
1074    }
1075    /// Calls `getUserChatBoosts` — returns the boosts added to a chat by a user.
1076    pub fn get_user_chat_boosts(
1077        &self,
1078        chat_id: impl Into<rustigram_types::user::ChatId>,
1079        user_id: i64,
1080    ) -> GetUserChatBoosts {
1081        GetUserChatBoosts::new(self.clone(), chat_id, user_id)
1082    }
1083    /// Calls `pinChatMessage` — pins a message in a chat.
1084    pub fn pin_chat_message(
1085        &self,
1086        chat_id: impl Into<rustigram_types::user::ChatId>,
1087        message_id: i64,
1088    ) -> PinChatMessage {
1089        PinChatMessage::new(self.clone(), chat_id, message_id)
1090    }
1091    /// Calls `unpinChatMessage` — unpins a message in a chat.
1092    pub fn unpin_chat_message(
1093        &self,
1094        chat_id: impl Into<rustigram_types::user::ChatId>,
1095    ) -> UnpinChatMessage {
1096        UnpinChatMessage::new(self.clone(), chat_id)
1097    }
1098
1099    // ── Bot settings ──────────────────────────────────────────────────────────
1100
1101    /// Calls `logOut` — logs the bot out of the cloud Bot API server.
1102    pub fn log_out(&self) -> LogOut {
1103        LogOut::new(self.clone())
1104    }
1105    /// Calls `close` — closes the bot instance before moving it to another server.
1106    pub fn close(&self) -> Close {
1107        Close::new(self.clone())
1108    }
1109    /// Calls `setMyCommands` — sets the bot's command list.
1110    pub fn set_my_commands(
1111        &self,
1112        commands: Vec<rustigram_types::user::BotCommand>,
1113    ) -> SetMyCommands {
1114        SetMyCommands::new(self.clone(), commands)
1115    }
1116    /// Calls `deleteMyCommands` — deletes the bot's command list for a given scope and language.
1117    pub fn delete_my_commands(&self) -> DeleteMyCommands {
1118        DeleteMyCommands::new(self.clone())
1119    }
1120    /// Calls `getMyCommands` — returns the bot's current command list.
1121    pub fn get_my_commands(&self) -> GetMyCommands {
1122        GetMyCommands::new(self.clone())
1123    }
1124    /// Calls `setMyName` — changes the bot's display name.
1125    pub fn set_my_name(&self) -> SetMyName {
1126        SetMyName::new(self.clone())
1127    }
1128    /// Calls `getMyName` — returns the bot's current display name.
1129    pub fn get_my_name(&self) -> GetMyName {
1130        GetMyName::new(self.clone())
1131    }
1132    /// Calls `setMyDescription` — changes the bot's profile description.
1133    pub fn set_my_description(&self) -> SetMyDescription {
1134        SetMyDescription::new(self.clone())
1135    }
1136    /// Calls `getMyDescription` — returns the bot's current profile description.
1137    pub fn get_my_description(&self) -> GetMyDescription {
1138        GetMyDescription::new(self.clone())
1139    }
1140    /// Calls `setMyShortDescription` — changes the bot's short description.
1141    pub fn set_my_short_description(&self) -> SetMyShortDescription {
1142        SetMyShortDescription::new(self.clone())
1143    }
1144    /// Calls `getMyShortDescription` — returns the bot's current short description.
1145    pub fn get_my_short_description(&self) -> GetMyShortDescription {
1146        GetMyShortDescription::new(self.clone())
1147    }
1148    /// Calls `setMyDefaultAdministratorRights` — sets the default admin rights suggested to users.
1149    pub fn set_my_default_administrator_rights(&self) -> SetMyDefaultAdministratorRights {
1150        SetMyDefaultAdministratorRights::new(self.clone())
1151    }
1152    /// Calls `getMyDefaultAdministratorRights` — returns the bot's current default admin rights.
1153    pub fn get_my_default_administrator_rights(&self) -> GetMyDefaultAdministratorRights {
1154        GetMyDefaultAdministratorRights::new(self.clone())
1155    }
1156    /// Calls `getChatMenuButton` — returns the current menu button for a private chat.
1157    pub fn get_chat_menu_button(&self) -> GetChatMenuButton {
1158        GetChatMenuButton::new(self.clone())
1159    }
1160    /// Calls `setChatMenuButton` — changes the bot's menu button in a private chat or globally.
1161    pub fn set_chat_menu_button(&self) -> SetChatMenuButton {
1162        SetChatMenuButton::new(self.clone())
1163    }
1164    /// Calls `setMyProfilePhoto` — changes the bot's profile photo (Bot API 9.4).
1165    ///
1166    /// Pass a pre-serialised `InputProfilePhoto` JSON string.
1167    pub fn set_my_profile_photo(&self, photo_json: impl Into<String>) -> SetMyProfilePhoto {
1168        SetMyProfilePhoto::new(self.clone(), photo_json.into())
1169    }
1170    /// Calls `removeMyProfilePhoto` — removes the bot's current profile photo (Bot API 9.4).
1171    pub fn remove_my_profile_photo(&self) -> RemoveMyProfilePhoto {
1172        RemoveMyProfilePhoto::new(self.clone())
1173    }
1174    /// Calls `getManagedBotToken` — returns the token of a managed bot (Bot API 9.6).
1175    pub fn get_managed_bot_token(&self, user_id: i64) -> GetManagedBotToken {
1176        GetManagedBotToken::new(self.clone(), user_id)
1177    }
1178    /// Calls `replaceManagedBotToken` — revokes and regenerates a managed bot's token (Bot API 9.6).
1179    pub fn replace_managed_bot_token(&self, user_id: i64) -> ReplaceManagedBotToken {
1180        ReplaceManagedBotToken::new(self.clone(), user_id)
1181    }
1182    /// Calls `getManagedBotAccessSettings` — returns the access settings of a managed bot (Bot API 9.7).
1183    pub fn get_managed_bot_access_settings(&self, user_id: i64) -> GetManagedBotAccessSettings {
1184        GetManagedBotAccessSettings::new(self.clone(), user_id)
1185    }
1186    /// Calls `setManagedBotAccessSettings` — changes the access settings of a managed bot (Bot API 9.7).
1187    pub fn set_managed_bot_access_settings(
1188        &self,
1189        user_id: i64,
1190        is_access_restricted: bool,
1191    ) -> SetManagedBotAccessSettings {
1192        SetManagedBotAccessSettings::new(self.clone(), user_id, is_access_restricted)
1193    }
1194
1195    // ── Stories (business bots) ───────────────────────────────────────────────
1196
1197    /// Calls `postStory` — posts a story on behalf of a managed business account.
1198    ///
1199    /// `content` is `serde_json::Value` until `InputStoryContent` is defined in Priority 4.
1200    /// `active_period` must be one of `21600`, `43200`, `86400`, or `172800` seconds.
1201    pub fn post_story(
1202        &self,
1203        business_connection_id: impl Into<String>,
1204        content: serde_json::Value,
1205        active_period: u32,
1206    ) -> PostStory {
1207        PostStory::new(self.clone(), business_connection_id, content, active_period)
1208    }
1209    /// Calls `repostStory` — reposts a story from one managed business account to another.
1210    ///
1211    /// `active_period` must be one of `21600`, `43200`, `86400`, or `172800` seconds.
1212    pub fn repost_story(
1213        &self,
1214        business_connection_id: impl Into<String>,
1215        from_chat_id: i64,
1216        from_story_id: i64,
1217        active_period: u32,
1218    ) -> RepostStory {
1219        RepostStory::new(
1220            self.clone(),
1221            business_connection_id,
1222            from_chat_id,
1223            from_story_id,
1224            active_period,
1225        )
1226    }
1227    /// Calls `editStory` — edits a story posted by the bot on behalf of a business account.
1228    ///
1229    /// `content` is `serde_json::Value` until `InputStoryContent` is defined in Priority 4.
1230    pub fn edit_story(
1231        &self,
1232        business_connection_id: impl Into<String>,
1233        story_id: i64,
1234        content: serde_json::Value,
1235    ) -> EditStory {
1236        EditStory::new(self.clone(), business_connection_id, story_id, content)
1237    }
1238    /// Calls `deleteStory` — deletes a story posted by the bot on behalf of a business account.
1239    pub fn delete_story(
1240        &self,
1241        business_connection_id: impl Into<String>,
1242        story_id: i64,
1243    ) -> DeleteStory {
1244        DeleteStory::new(self.clone(), business_connection_id, story_id)
1245    }
1246
1247    // ── Gifts ─────────────────────────────────────────────────────────────────
1248
1249    /// Calls `getAvailableGifts` — returns all gifts the bot can send.
1250    pub fn get_available_gifts(&self) -> GetAvailableGifts {
1251        GetAvailableGifts::new(self.clone())
1252    }
1253    /// Calls `sendGift` — sends a gift to a user or channel chat.
1254    ///
1255    /// Chain `.user_id(id)` or `.chat_id(id)` to specify the recipient.
1256    pub fn send_gift(&self, gift_id: impl Into<String>) -> SendGift {
1257        SendGift::new(self.clone(), gift_id)
1258    }
1259    /// Calls `giftPremiumSubscription` — gifts a Telegram Premium subscription to a user.
1260    ///
1261    /// `month_count` must be `3`, `6`, or `12`.
1262    /// `star_count` must be `1000`, `1500`, or `2500` respectively.
1263    pub fn gift_premium_subscription(
1264        &self,
1265        user_id: i64,
1266        month_count: u32,
1267        star_count: u32,
1268    ) -> GiftPremiumSubscription {
1269        GiftPremiumSubscription::new(self.clone(), user_id, month_count, star_count)
1270    }
1271    /// Calls `getBusinessAccountGifts` — returns gifts received by a managed business account.
1272    pub fn get_business_account_gifts(
1273        &self,
1274        business_connection_id: impl Into<String>,
1275    ) -> GetBusinessAccountGifts {
1276        GetBusinessAccountGifts::new(self.clone(), business_connection_id)
1277    }
1278    /// Calls `getUserGifts` — returns gifts owned by a user.
1279    pub fn get_user_gifts(&self, user_id: i64) -> GetUserGifts {
1280        GetUserGifts::new(self.clone(), user_id)
1281    }
1282    /// Calls `getChatGifts` — returns gifts owned by a channel chat.
1283    pub fn get_chat_gifts(
1284        &self,
1285        chat_id: impl Into<rustigram_types::user::ChatId>,
1286    ) -> GetChatGifts {
1287        GetChatGifts::new(self.clone(), chat_id)
1288    }
1289    /// Calls `convertGiftToStars` — converts a business account gift to Telegram Stars.
1290    pub fn convert_gift_to_stars(
1291        &self,
1292        business_connection_id: impl Into<String>,
1293        owned_gift_id: impl Into<String>,
1294    ) -> ConvertGiftToStars {
1295        ConvertGiftToStars::new(self.clone(), business_connection_id, owned_gift_id)
1296    }
1297    /// Calls `upgradeGift` — upgrades a regular gift to a unique gift.
1298    pub fn upgrade_gift(
1299        &self,
1300        business_connection_id: impl Into<String>,
1301        owned_gift_id: impl Into<String>,
1302    ) -> UpgradeGift {
1303        UpgradeGift::new(self.clone(), business_connection_id, owned_gift_id)
1304    }
1305    /// Calls `transferGift` — transfers a unique gift to another user.
1306    pub fn transfer_gift(
1307        &self,
1308        business_connection_id: impl Into<String>,
1309        owned_gift_id: impl Into<String>,
1310        new_owner_chat_id: i64,
1311    ) -> TransferGift {
1312        TransferGift::new(
1313            self.clone(),
1314            business_connection_id,
1315            owned_gift_id,
1316            new_owner_chat_id,
1317        )
1318    }
1319
1320    // ── Reactions ─────────────────────────────────────────────────────────────
1321
1322    /// Calls `setMessageReaction` — sets a reaction on a message.
1323    pub fn set_message_reaction(
1324        &self,
1325        chat_id: impl Into<rustigram_types::user::ChatId>,
1326        message_id: i64,
1327    ) -> SetMessageReaction {
1328        SetMessageReaction::new(self.clone(), chat_id, message_id)
1329    }
1330    /// Calls `deleteMessageReaction` — removes a specific reaction from a message (Bot API 9.7).
1331    pub fn delete_message_reaction(
1332        &self,
1333        chat_id: impl Into<rustigram_types::user::ChatId>,
1334        message_id: i64,
1335    ) -> DeleteMessageReaction {
1336        DeleteMessageReaction::new(self.clone(), chat_id, message_id)
1337    }
1338    /// Calls `deleteAllMessageReactions` — removes all recent reactions by a given user or chat (Bot API 9.7).
1339    pub fn delete_all_message_reactions(
1340        &self,
1341        chat_id: impl Into<rustigram_types::user::ChatId>,
1342    ) -> DeleteAllMessageReactions {
1343        DeleteAllMessageReactions::new(self.clone(), chat_id)
1344    }
1345
1346    // ── Inline mode ───────────────────────────────────────────────────────────
1347
1348    /// Calls `answerInlineQuery` — sends up to 50 results for an inline query.
1349    pub fn answer_inline_query(
1350        &self,
1351        inline_query_id: impl Into<String>,
1352        results: Vec<rustigram_types::inline::InlineQueryResult>,
1353    ) -> AnswerInlineQuery {
1354        AnswerInlineQuery::new(self.clone(), inline_query_id, results)
1355    }
1356    /// Calls `answerWebAppQuery` — sets the result of a Web App interaction and sends it to the chat.
1357    pub fn answer_web_app_query(
1358        &self,
1359        web_app_query_id: impl Into<String>,
1360        result: rustigram_types::inline::InlineQueryResult,
1361    ) -> AnswerWebAppQuery {
1362        AnswerWebAppQuery::new(self.clone(), web_app_query_id, result)
1363    }
1364    /// Calls `answerGuestQuery` — replies to a received guest message (Bot API 9.7).
1365    pub fn answer_guest_query(
1366        &self,
1367        guest_query_id: impl Into<String>,
1368        result: rustigram_types::inline::InlineQueryResult,
1369    ) -> AnswerGuestQuery {
1370        AnswerGuestQuery::new(self.clone(), guest_query_id, result)
1371    }
1372    /// Calls `savePreparedInlineMessage` — stores a message sendable by a Mini App user.
1373    pub fn save_prepared_inline_message(
1374        &self,
1375        user_id: i64,
1376        result: rustigram_types::inline::InlineQueryResult,
1377    ) -> SavePreparedInlineMessage {
1378        SavePreparedInlineMessage::new(self.clone(), user_id, result)
1379    }
1380
1381    // ── Mini App ──────────────────────────────────────────────────────────────
1382
1383    /// Calls `savePreparedKeyboardButton` — stores a keyboard button for use in a Mini App (Bot API 9.6).
1384    ///
1385    /// The button must be of type `request_users`, `request_chat`, or `request_managed_bot`.
1386    pub fn save_prepared_keyboard_button(
1387        &self,
1388        user_id: i64,
1389        button: rustigram_types::keyboard::KeyboardButton,
1390    ) -> SavePreparedKeyboardButton {
1391        SavePreparedKeyboardButton::new(self.clone(), user_id, button)
1392    }
1393    /// Calls `setUserEmojiStatus` — changes a user's emoji status via a Mini App.
1394    pub fn set_user_emoji_status(&self, user_id: i64) -> SetUserEmojiStatus {
1395        SetUserEmojiStatus::new(self.clone(), user_id)
1396    }
1397
1398    // ── Passport ──────────────────────────────────────────────────────────────
1399
1400    /// Calls `setPassportDataErrors` — reports errors in Telegram Passport elements.
1401    ///
1402    /// Each error is a `serde_json::Value` — serialise from
1403    /// `rustigram_types::passport::PassportElementError` variants.
1404    pub fn set_passport_data_errors(
1405        &self,
1406        user_id: i64,
1407        errors: Vec<serde_json::Value>,
1408    ) -> SetPassportDataErrors {
1409        SetPassportDataErrors::new(self.clone(), user_id, errors)
1410    }
1411
1412    // ── Games ─────────────────────────────────────────────────────────────────
1413
1414    /// Calls `setGameScore` — sets a user's score in a game.
1415    ///
1416    /// Chain `.chat_message(chat_id, message_id)` or `.inline_message_id(id)` to target the message.
1417    pub fn set_game_score(&self, user_id: i64, score: u32) -> SetGameScore {
1418        SetGameScore::new(self.clone(), user_id, score)
1419    }
1420    /// Calls `getGameHighScores` — returns high scores for a game.
1421    ///
1422    /// Chain `.chat_message(chat_id, message_id)` or `.inline_message_id(id)` to target the message.
1423    pub fn get_game_high_scores(&self, user_id: i64) -> GetGameHighScores {
1424        GetGameHighScores::new(self.clone(), user_id)
1425    }
1426
1427    // ── Payments ──────────────────────────────────────────────────────────────
1428
1429    /// Calls `sendInvoice` — sends a payment invoice.
1430    pub fn send_invoice(
1431        &self,
1432        chat_id: impl Into<rustigram_types::user::ChatId>,
1433        title: impl Into<String>,
1434        description: impl Into<String>,
1435        payload: impl Into<String>,
1436        currency: impl Into<String>,
1437        prices: Vec<rustigram_types::payments::LabeledPrice>,
1438    ) -> SendInvoice {
1439        SendInvoice::new(
1440            self.clone(),
1441            chat_id,
1442            title,
1443            description,
1444            payload,
1445            currency,
1446            prices,
1447        )
1448    }
1449    /// Calls `createInvoiceLink` — creates a shareable payment link.
1450    pub fn create_invoice_link(
1451        &self,
1452        title: impl Into<String>,
1453        description: impl Into<String>,
1454        payload: impl Into<String>,
1455        currency: impl Into<String>,
1456        prices: Vec<rustigram_types::payments::LabeledPrice>,
1457    ) -> CreateInvoiceLink {
1458        CreateInvoiceLink::new(self.clone(), title, description, payload, currency, prices)
1459    }
1460    /// Calls `answerShippingQuery` — responds to a shipping query from a user.
1461    ///
1462    /// Pass `ok = true` and provide `shipping_options`; or `ok = false` with an `error_message`.
1463    pub fn answer_shipping_query(
1464        &self,
1465        shipping_query_id: impl Into<String>,
1466        ok: bool,
1467    ) -> AnswerShippingQuery {
1468        AnswerShippingQuery::new(self.clone(), shipping_query_id, ok)
1469    }
1470    /// Calls `answerPreCheckoutQuery` — confirms or rejects a pre-checkout query.
1471    ///
1472    /// Must be called within **10 seconds** of receiving the query.
1473    pub fn answer_pre_checkout_query(
1474        &self,
1475        pre_checkout_query_id: impl Into<String>,
1476        ok: bool,
1477    ) -> AnswerPreCheckoutQuery {
1478        AnswerPreCheckoutQuery::new(self.clone(), pre_checkout_query_id, ok)
1479    }
1480    /// Calls `refundStarPayment` — refunds a successful Telegram Stars payment.
1481    pub fn refund_star_payment(
1482        &self,
1483        user_id: i64,
1484        telegram_payment_charge_id: impl Into<String>,
1485    ) -> RefundStarPayment {
1486        RefundStarPayment::new(self.clone(), user_id, telegram_payment_charge_id)
1487    }
1488    /// Calls `editUserStarSubscription` — cancels or re-enables a Stars subscription.
1489    pub fn edit_user_star_subscription(
1490        &self,
1491        user_id: i64,
1492        telegram_payment_charge_id: impl Into<String>,
1493        is_canceled: bool,
1494    ) -> EditUserStarSubscription {
1495        EditUserStarSubscription::new(
1496            self.clone(),
1497            user_id,
1498            telegram_payment_charge_id,
1499            is_canceled,
1500        )
1501    }
1502    /// Calls `getMyStarBalance` — returns the bot's Telegram Star balance.
1503    pub fn get_my_star_balance(&self) -> GetMyStarBalance {
1504        GetMyStarBalance::new(self.clone())
1505    }
1506    /// Calls `getStarTransactions` — returns the bot's Star transaction history.
1507    pub fn get_star_transactions(&self) -> GetStarTransactions {
1508        GetStarTransactions::new(self.clone())
1509    }
1510
1511    // ── Stickers ──────────────────────────────────────────────────────────────
1512
1513    /// Calls `getStickerSet` — returns a sticker set by name.
1514    pub fn get_sticker_set(&self, name: impl Into<String>) -> GetStickerSet {
1515        GetStickerSet::new(self.clone(), name)
1516    }
1517    /// Calls `getCustomEmojiStickers` — returns stickers for the given custom emoji IDs.
1518    pub fn get_custom_emoji_stickers(&self, ids: Vec<impl Into<String>>) -> GetCustomEmojiStickers {
1519        GetCustomEmojiStickers::new(self.clone(), ids)
1520    }
1521    /// Calls `uploadStickerFile` — uploads a sticker file for later use in a set.
1522    pub fn upload_sticker_file(
1523        &self,
1524        user_id: i64,
1525        sticker: rustigram_types::file::InputFile,
1526        format: rustigram_types::sticker::StickerFormat,
1527    ) -> UploadStickerFile {
1528        UploadStickerFile::new(self.clone(), user_id, sticker, format)
1529    }
1530    /// Calls `createNewStickerSet` — creates a new sticker set owned by a user.
1531    pub fn create_new_sticker_set(
1532        &self,
1533        user_id: i64,
1534        name: impl Into<String>,
1535        title: impl Into<String>,
1536        stickers: Vec<rustigram_types::sticker::InputSticker>,
1537    ) -> CreateNewStickerSet {
1538        CreateNewStickerSet::new(self.clone(), user_id, name, title, stickers)
1539    }
1540    /// Calls `addStickerToSet` — adds a new sticker to an existing set.
1541    pub fn add_sticker_to_set(
1542        &self,
1543        user_id: i64,
1544        name: impl Into<String>,
1545        sticker: rustigram_types::sticker::InputSticker,
1546    ) -> AddStickerToSet {
1547        AddStickerToSet::new(self.clone(), user_id, name, sticker)
1548    }
1549    /// Calls `setStickerPositionInSet` — moves a sticker to a new position in its set.
1550    pub fn set_sticker_position_in_set(
1551        &self,
1552        sticker: impl Into<String>,
1553        position: u32,
1554    ) -> SetStickerPositionInSet {
1555        SetStickerPositionInSet::new(self.clone(), sticker, position)
1556    }
1557    /// Calls `deleteStickerFromSet` — removes a sticker from its set.
1558    pub fn delete_sticker_from_set(&self, sticker: impl Into<String>) -> DeleteStickerFromSet {
1559        DeleteStickerFromSet::new(self.clone(), sticker)
1560    }
1561    /// Calls `setStickerEmojiList` — updates the emoji list for a sticker.
1562    pub fn set_sticker_emoji_list(
1563        &self,
1564        sticker: impl Into<String>,
1565        emoji_list: Vec<impl Into<String>>,
1566    ) -> SetStickerEmojiList {
1567        SetStickerEmojiList::new(self.clone(), sticker, emoji_list)
1568    }
1569    /// Calls `setStickerKeywords` — updates the search keywords for a sticker.
1570    pub fn set_sticker_keywords(&self, sticker: impl Into<String>) -> SetStickerKeywords {
1571        SetStickerKeywords::new(self.clone(), sticker)
1572    }
1573    /// Calls `setStickerMaskPosition` — updates the mask position for a mask sticker.
1574    pub fn set_sticker_mask_position(&self, sticker: impl Into<String>) -> SetStickerMaskPosition {
1575        SetStickerMaskPosition::new(self.clone(), sticker)
1576    }
1577    /// Calls `setStickerSetTitle` — renames a sticker set.
1578    pub fn set_sticker_set_title(
1579        &self,
1580        name: impl Into<String>,
1581        title: impl Into<String>,
1582    ) -> SetStickerSetTitle {
1583        SetStickerSetTitle::new(self.clone(), name, title)
1584    }
1585    /// Calls `deleteStickerSet` — deletes a sticker set created by the bot.
1586    pub fn delete_sticker_set(&self, name: impl Into<String>) -> DeleteStickerSet {
1587        DeleteStickerSet::new(self.clone(), name)
1588    }
1589    /// Calls `replaceStickerInSet` — replaces an existing sticker in a set with a new one.
1590    pub fn replace_sticker_in_set(
1591        &self,
1592        user_id: i64,
1593        name: impl Into<String>,
1594        old_sticker: impl Into<String>,
1595        sticker: rustigram_types::sticker::InputSticker,
1596    ) -> ReplaceStickerInSet {
1597        ReplaceStickerInSet::new(self.clone(), user_id, name, old_sticker, sticker)
1598    }
1599    /// Calls `setStickerSetThumbnail` — sets the thumbnail of a regular or mask sticker set.
1600    ///
1601    /// `format` must be `"static"`, `"animated"`, or `"video"`.
1602    /// Chain `.thumbnail(file)` to set the thumbnail; omit to drop it.
1603    pub fn set_sticker_set_thumbnail(
1604        &self,
1605        name: impl Into<String>,
1606        user_id: i64,
1607        format: impl Into<String>,
1608    ) -> SetStickerSetThumbnail {
1609        SetStickerSetThumbnail::new(self.clone(), name, user_id, format)
1610    }
1611    /// Calls `setCustomEmojiStickerSetThumbnail` — sets the thumbnail of a custom emoji sticker set.
1612    ///
1613    /// Chain `.custom_emoji_id(id)` to set the thumbnail emoji; omit to use the first sticker.
1614    pub fn set_custom_emoji_sticker_set_thumbnail(
1615        &self,
1616        name: impl Into<String>,
1617    ) -> SetCustomEmojiStickerSetThumbnail {
1618        SetCustomEmojiStickerSetThumbnail::new(self.clone(), name)
1619    }
1620    /// Calls `getForumTopicIconStickers` — returns all available forum topic icon stickers.
1621    pub fn get_forum_topic_icon_stickers(&self) -> GetForumTopicIconStickers {
1622        GetForumTopicIconStickers::new(self.clone())
1623    }
1624
1625    // ── Forum topics ──────────────────────────────────────────────────────────
1626
1627    /// Calls `createForumTopic` — creates a new topic in a forum supergroup.
1628    pub fn create_forum_topic(
1629        &self,
1630        chat_id: impl Into<rustigram_types::user::ChatId>,
1631        name: impl Into<String>,
1632    ) -> CreateForumTopic {
1633        CreateForumTopic::new(self.clone(), chat_id, name)
1634    }
1635    /// Calls `editForumTopic` — edits the name or icon of a forum topic.
1636    pub fn edit_forum_topic(
1637        &self,
1638        chat_id: impl Into<rustigram_types::user::ChatId>,
1639        thread_id: i64,
1640    ) -> EditForumTopic {
1641        EditForumTopic::new(self.clone(), chat_id, thread_id)
1642    }
1643    /// Calls `closeForumTopic` — closes an open forum topic.
1644    pub fn close_forum_topic(
1645        &self,
1646        chat_id: impl Into<rustigram_types::user::ChatId>,
1647        thread_id: i64,
1648    ) -> CloseForumTopic {
1649        CloseForumTopic::new(self.clone(), chat_id, thread_id)
1650    }
1651    /// Calls `reopenForumTopic` — reopens a closed forum topic.
1652    pub fn reopen_forum_topic(
1653        &self,
1654        chat_id: impl Into<rustigram_types::user::ChatId>,
1655        thread_id: i64,
1656    ) -> ReopenForumTopic {
1657        ReopenForumTopic::new(self.clone(), chat_id, thread_id)
1658    }
1659    /// Calls `deleteForumTopic` — deletes a forum topic and all its messages.
1660    pub fn delete_forum_topic(
1661        &self,
1662        chat_id: impl Into<rustigram_types::user::ChatId>,
1663        thread_id: i64,
1664    ) -> DeleteForumTopic {
1665        DeleteForumTopic::new(self.clone(), chat_id, thread_id)
1666    }
1667    /// Calls `editGeneralForumTopic` — renames the General topic.
1668    pub fn edit_general_forum_topic(
1669        &self,
1670        chat_id: impl Into<rustigram_types::user::ChatId>,
1671        name: impl Into<String>,
1672    ) -> EditGeneralForumTopic {
1673        EditGeneralForumTopic::new(self.clone(), chat_id, name)
1674    }
1675    /// Calls `closeGeneralForumTopic` — closes the General topic.
1676    pub fn close_general_forum_topic(
1677        &self,
1678        chat_id: impl Into<rustigram_types::user::ChatId>,
1679    ) -> CloseGeneralForumTopic {
1680        CloseGeneralForumTopic::new(self.clone(), chat_id)
1681    }
1682    /// Calls `reopenGeneralForumTopic` — reopens the General topic.
1683    pub fn reopen_general_forum_topic(
1684        &self,
1685        chat_id: impl Into<rustigram_types::user::ChatId>,
1686    ) -> ReopenGeneralForumTopic {
1687        ReopenGeneralForumTopic::new(self.clone(), chat_id)
1688    }
1689    /// Calls `hideGeneralForumTopic` — hides the General topic from the topic list.
1690    pub fn hide_general_forum_topic(
1691        &self,
1692        chat_id: impl Into<rustigram_types::user::ChatId>,
1693    ) -> HideGeneralForumTopic {
1694        HideGeneralForumTopic::new(self.clone(), chat_id)
1695    }
1696    /// Calls `unhideGeneralForumTopic` — makes the General topic visible again.
1697    pub fn unhide_general_forum_topic(
1698        &self,
1699        chat_id: impl Into<rustigram_types::user::ChatId>,
1700    ) -> UnhideGeneralForumTopic {
1701        UnhideGeneralForumTopic::new(self.clone(), chat_id)
1702    }
1703    /// Calls `unpinAllGeneralForumTopicMessages` — clears all pinned messages in the General forum topic.
1704    pub fn unpin_all_general_forum_topic_messages(
1705        &self,
1706        chat_id: impl Into<rustigram_types::user::ChatId>,
1707    ) -> UnpinAllGeneralForumTopicMessages {
1708        UnpinAllGeneralForumTopicMessages::new(self.clone(), chat_id)
1709    }
1710
1711    // ── Verification ──────────────────────────────────────────────────────────
1712
1713    /// Calls `verifyUser` — verifies a user on behalf of the organisation.
1714    pub fn verify_user(&self, user_id: i64) -> VerifyUser {
1715        VerifyUser::new(self.clone(), user_id)
1716    }
1717    /// Calls `verifyChat` — verifies a chat on behalf of the organisation.
1718    pub fn verify_chat(&self, chat_id: impl Into<rustigram_types::user::ChatId>) -> VerifyChat {
1719        VerifyChat::new(self.clone(), chat_id)
1720    }
1721    /// Calls `removeUserVerification` — removes verification from a user.
1722    pub fn remove_user_verification(&self, user_id: i64) -> RemoveUserVerification {
1723        RemoveUserVerification::new(self.clone(), user_id)
1724    }
1725    /// Calls `removeChatVerification` — removes verification from a chat.
1726    pub fn remove_chat_verification(
1727        &self,
1728        chat_id: impl Into<rustigram_types::user::ChatId>,
1729    ) -> RemoveChatVerification {
1730        RemoveChatVerification::new(self.clone(), chat_id)
1731    }
1732
1733    // ── Business account ──────────────────────────────────────────────────────
1734
1735    /// Calls `getBusinessConnection` — returns business connection information.
1736    pub fn get_business_connection(&self, id: impl Into<String>) -> GetBusinessConnection {
1737        GetBusinessConnection::new(self.clone(), id)
1738    }
1739    /// Calls `readBusinessMessage` — marks a business account message as read.
1740    pub fn read_business_message(
1741        &self,
1742        business_connection_id: impl Into<String>,
1743        chat_id: impl Into<rustigram_types::user::ChatId>,
1744        message_id: i64,
1745    ) -> ReadBusinessMessage {
1746        ReadBusinessMessage::new(self.clone(), business_connection_id, chat_id, message_id)
1747    }
1748    /// Calls `deleteBusinessMessages` — deletes messages from a business account.
1749    pub fn delete_business_messages(
1750        &self,
1751        business_connection_id: impl Into<String>,
1752        message_ids: Vec<i64>,
1753    ) -> DeleteBusinessMessages {
1754        DeleteBusinessMessages::new(self.clone(), business_connection_id, message_ids)
1755    }
1756    /// Calls `setBusinessAccountName` — sets the name of a managed business account.
1757    pub fn set_business_account_name(
1758        &self,
1759        business_connection_id: impl Into<String>,
1760        first_name: impl Into<String>,
1761        last_name: Option<String>,
1762    ) -> SetBusinessAccountName {
1763        SetBusinessAccountName::new(
1764            self.clone(),
1765            business_connection_id,
1766            first_name.into(),
1767            last_name,
1768        )
1769    }
1770    /// Calls `setBusinessAccountUsername` — sets the username of a managed business account.
1771    pub fn set_business_account_username(
1772        &self,
1773        business_connection_id: impl Into<String>,
1774        username: Option<String>,
1775    ) -> SetBusinessAccountUsername {
1776        SetBusinessAccountUsername::new(self.clone(), business_connection_id, username)
1777    }
1778    /// Calls `setBusinessAccountBio` — sets the bio of a managed business account.
1779    pub fn set_business_account_bio(
1780        &self,
1781        business_connection_id: impl Into<String>,
1782        bio: Option<String>,
1783    ) -> SetBusinessAccountBio {
1784        SetBusinessAccountBio::new(self.clone(), business_connection_id, bio)
1785    }
1786    /// Calls `getBusinessAccountStarBalance` — returns a business account's Star balance.
1787    pub fn get_business_account_star_balance(
1788        &self,
1789        business_connection_id: impl Into<String>,
1790    ) -> GetBusinessAccountStarBalance {
1791        GetBusinessAccountStarBalance::new(self.clone(), business_connection_id)
1792    }
1793    /// Calls `transferBusinessAccountStars` — transfers Stars from a business account to the bot.
1794    pub fn transfer_business_account_stars(
1795        &self,
1796        business_connection_id: impl Into<String>,
1797        star_count: u64,
1798    ) -> TransferBusinessAccountStars {
1799        TransferBusinessAccountStars::new(self.clone(), business_connection_id, star_count)
1800    }
1801    /// Calls `unpinAllForumTopicMessages` — clears all pinned messages in a forum topic.
1802    pub fn unpin_all_forum_topic_messages(
1803        &self,
1804        chat_id: impl Into<rustigram_types::user::ChatId>,
1805        thread_id: i64,
1806    ) -> UnpinAllForumTopicMessages {
1807        UnpinAllForumTopicMessages::new(self.clone(), chat_id, thread_id)
1808    }
1809
1810    /// Calls `setBusinessAccountProfilePhoto` — sets the profile photo of a managed business account.
1811    ///
1812    /// Pass `photo` as `serde_json::to_value(&input_profile_photo)`.
1813    pub fn set_business_account_profile_photo(
1814        &self,
1815        business_connection_id: impl Into<String>,
1816        photo: serde_json::Value,
1817    ) -> SetBusinessAccountProfilePhoto {
1818        SetBusinessAccountProfilePhoto::new(self.clone(), business_connection_id, photo)
1819    }
1820
1821    /// Calls `removeBusinessAccountProfilePhoto` — removes the profile photo of a managed business account.
1822    pub fn remove_business_account_profile_photo(
1823        &self,
1824        business_connection_id: impl Into<String>,
1825    ) -> RemoveBusinessAccountProfilePhoto {
1826        RemoveBusinessAccountProfilePhoto::new(self.clone(), business_connection_id)
1827    }
1828
1829    /// Calls `setBusinessAccountGiftSettings` — changes gift privacy settings for a managed business account.
1830    pub fn set_business_account_gift_settings(
1831        &self,
1832        business_connection_id: impl Into<String>,
1833        show_gift_button: bool,
1834        accepted_gift_types: rustigram_types::payments::AcceptedGiftTypes,
1835    ) -> SetBusinessAccountGiftSettings {
1836        SetBusinessAccountGiftSettings::new(
1837            self.clone(),
1838            business_connection_id,
1839            show_gift_button,
1840            accepted_gift_types,
1841        )
1842    }
1843}
1844
1845// ─── Helpers ──────────────────────────────────────────────────────────────────
1846
1847#[allow(dead_code)]
1848/// Converts an `InputFile::Bytes` into a multipart `Part` for file uploads.
1849pub(crate) fn input_file_to_part(file: rustigram_types::file::InputFile) -> Option<(String, Part)> {
1850    use rustigram_types::file::InputFile;
1851    match file {
1852        InputFile::Bytes {
1853            filename,
1854            data,
1855            mime_type,
1856        } => {
1857            let part = Part::bytes(data)
1858                .file_name(filename.clone())
1859                .mime_str(&mime_type)
1860                .ok()?;
1861            Some((filename, part))
1862        }
1863        _ => None,
1864    }
1865}
1866
1867fn validate_token(token: &str) -> Result<()> {
1868    let colon = token.find(':').ok_or(Error::InvalidToken)?;
1869    let id_part = &token[..colon];
1870    if id_part.is_empty() || !id_part.chars().all(|c| c.is_ascii_digit()) {
1871        return Err(Error::InvalidToken);
1872    }
1873    if token[colon + 1..].is_empty() {
1874        return Err(Error::InvalidToken);
1875    }
1876    Ok(())
1877}