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