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