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