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