diff --git a/Cargo.toml b/Cargo.toml
index 6c7b54f3..6b662740 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
 [package]
-name = "async-telegram-bot"
+name = "telebofr"
 version = "0.1.0"
 edition = "2018"
 
diff --git a/LICENSE b/LICENSE
index 75a50a58..edb41b3e 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2019 async-telegram-bot
+Copyright (c) 2019 telebofr
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 1a35a603..299433df 100644
--- a/README.md
+++ b/README.md
@@ -1,30 +1,20 @@
 
 <div align="center">
-  <h1>async-telegram-bot</h1>
+  <img src="ICON.png" width="200"/>
+  <h1>telebofr</h1>
   
-  <a href="https://docs.rs/async-telegram-bot/">
+  <a href="https://docs.rs/telebofr/">
     <img src="https://img.shields.io/badge/docs.rs-link-blue.svg">
   </a>
-  <a href="https://travis-ci.com/async-telegram-bot/async-telegram-bot">
-    <img src="https://travis-ci.com/async-telegram-bot/async-telegram-bot.svg?branch=dev" />
+  <a href="https://travis-ci.com/telebofr/telebofr">
+    <img src="https://travis-ci.com/telebofr/telebofr.svg?branch=dev" />
   </a>
   <a href="LICENSE">
     <img src="https://img.shields.io/badge/license-MIT-blue.svg">
   </a>
-  <a href="https://crates.io/crates/async-telegram-bot">
+  <a href="https://crates.io/crates/telebofr">
     <img src="https://img.shields.io/badge/crates.io-v0.1.0-orange.svg">
   </a>
   
-  <br>
-  <img src="ICON.png" width="300"/>
-  <br>
-  
   A full-featured framework that empowers you to easily build [Telegram bots](https://telegram.org/blog/bot-revolution) using the [`async`/`.await`](https://rust-lang.github.io/async-book/01_getting_started/01_chapter.html) syntax in [Rust](https://www.rust-lang.org/). It handles all the difficult stuff so you can focus only on your business logic.
 </div>
-
-## A simple bot
-```rust
-fn main() {
-  let bot = Bot::new(API_TOKEN).bla().bla();
-}
-```
diff --git a/hw.doc b/hw.doc
new file mode 100644
index 00000000..0bdb82bf
Binary files /dev/null and b/hw.doc differ
diff --git a/rustfmt.toml b/rustfmt.toml
index f99a2b6f..cee9b586 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,4 +1,5 @@
 format_code_in_doc_comments = true
 wrap_comments = true
 format_strings = true
-max_width = 80
\ No newline at end of file
+max_width = 80
+merge_imports = true
\ No newline at end of file
diff --git a/src/bot/api.rs b/src/bot/api.rs
index a75328c1..7a43b6c1 100644
--- a/src/bot/api.rs
+++ b/src/bot/api.rs
@@ -1,24 +1,28 @@
 use crate::{
     bot::Bot,
     requests::{
-        AnswerPreCheckoutQuery, AnswerShippingQuery, EditMessageLiveLocation,
-        ForwardMessage, GetFile, GetMe, KickChatMember, PinChatMessage,
-        PromoteChatMember, RestrictChatMember, SendAudio, SendChatAction,
-        SendContact, SendLocation, SendMediaGroup, SendMessage, SendPhoto,
-        SendPoll, SendVenue, SendVideoNote, SendVoice, StopMessageLiveLocation,
-        UnbanChatMember, UnpinChatMessage, GetUpdates
+        AnswerCallbackQuery, AnswerPreCheckoutQuery, AnswerShippingQuery,
+        DeleteChatPhoto, DeleteChatStickerSet, EditMessageLiveLocation,
+        ExportCharInviteLink, ForwardMessage, GetChat, GetChatAdministrators,
+        GetChatMember, GetChatMembersCount, GetFile, GetMe, GetUpdates,
+        KickChatMember, LeaveChat, PinChatMessage, PromoteChatMember,
+        RestrictChatMember, SendAnimation, SendAudio, SendChatAction,
+        SendContact, SendDocument, SendLocation, SendMediaGroup, SendMessage,
+        SendPhoto, SendPoll, SendVenue, SendVideo, SendVideoNote, SendVoice,
+        SetChatDescription, SetChatPermissions, SetChatPhoto,
+        SetChatStickerSet, SetChatTitle, StopMessageLiveLocation,
+        UnbanChatMember, UnpinChatMessage,
     },
     types::{ChatAction, ChatId, ChatPermissions, InputFile, InputMedia},
 };
 
-/// Telegram functions
 impl Bot {
     pub fn get_me(&self) -> GetMe {
-        GetMe::new(self.ctx())
+        GetMe::new(self)
     }
 
     pub fn get_updates(&self) -> GetUpdates {
-        GetUpdates::new(self.ctx())
+        GetUpdates::new(self)
     }
 
     pub fn send_message<C, T>(&self, chat_id: C, text: T) -> SendMessage
@@ -26,7 +30,7 @@ impl Bot {
         C: Into<ChatId>,
         T: Into<String>,
     {
-        SendMessage::new(self.ctx(), chat_id, text)
+        SendMessage::new(self, chat_id, text)
     }
 
     pub fn edit_message_live_location<Lt, Lg>(
@@ -38,7 +42,7 @@ impl Bot {
         Lt: Into<f64>,
         Lg: Into<f64>,
     {
-        EditMessageLiveLocation::new(self.ctx(), latitude, longitude)
+        EditMessageLiveLocation::new(self, latitude, longitude)
     }
 
     pub fn forward_message<C, F, M>(
@@ -52,7 +56,7 @@ impl Bot {
         F: Into<ChatId>,
         M: Into<i32>,
     {
-        ForwardMessage::new(self.ctx(), chat_id, from_chat_id, message_id)
+        ForwardMessage::new(self, chat_id, from_chat_id, message_id)
     }
 
     pub fn send_audio<C, A>(&self, chat_id: C, audio: A) -> SendAudio
@@ -60,7 +64,7 @@ impl Bot {
         C: Into<ChatId>,
         A: Into<InputFile>,
     {
-        SendAudio::new(self.ctx(), chat_id, audio)
+        SendAudio::new(self, chat_id, audio)
     }
 
     pub fn send_location<C, Lt, Lg>(
@@ -74,7 +78,7 @@ impl Bot {
         Lt: Into<f64>,
         Lg: Into<f64>,
     {
-        SendLocation::new(self.ctx(), chat_id, latitude, longitude)
+        SendLocation::new(self, chat_id, latitude, longitude)
     }
 
     pub fn send_media_group<C, M>(&self, chat_id: C, media: M) -> SendMediaGroup
@@ -82,7 +86,7 @@ impl Bot {
         C: Into<ChatId>,
         M: Into<Vec<InputMedia>>,
     {
-        SendMediaGroup::new(self.ctx(), chat_id, media)
+        SendMediaGroup::new(self, chat_id, media)
     }
 
     pub fn send_photo<C, P>(&self, chat_id: C, photo: P) -> SendPhoto
@@ -90,18 +94,18 @@ impl Bot {
         C: Into<ChatId>,
         P: Into<InputFile>,
     {
-        SendPhoto::new(self.ctx(), chat_id, photo)
+        SendPhoto::new(self, chat_id, photo)
     }
 
     pub fn stop_message_live_location(&self) -> StopMessageLiveLocation {
-        StopMessageLiveLocation::new(self.ctx())
+        StopMessageLiveLocation::new(self)
     }
 
     pub fn get_file<F>(&self, file_id: F) -> GetFile
     where
         F: Into<String>,
     {
-        GetFile::new(self.ctx(), file_id)
+        GetFile::new(self, file_id)
     }
 
     pub fn answer_pre_checkout_query<I, O>(
@@ -113,7 +117,14 @@ impl Bot {
         I: Into<String>,
         O: Into<bool>,
     {
-        AnswerPreCheckoutQuery::new(self.ctx(), pre_checkout_query_id, ok)
+        AnswerPreCheckoutQuery::new(self, pre_checkout_query_id, ok)
+    }
+
+    pub fn get_chat<I>(&self, chat_id: I) -> GetChat
+    where
+        I: Into<ChatId>,
+    {
+        GetChat::new(self, chat_id)
     }
 
     pub fn answer_shipping_query<I, O>(
@@ -125,7 +136,7 @@ impl Bot {
         I: Into<String>,
         O: Into<bool>,
     {
-        AnswerShippingQuery::new(self.ctx(), shipping_query_id, ok)
+        AnswerShippingQuery::new(self, shipping_query_id, ok)
     }
 
     pub fn kick_chat_member<C, U>(
@@ -137,7 +148,7 @@ impl Bot {
         C: Into<ChatId>,
         U: Into<i32>,
     {
-        KickChatMember::new(self.ctx(), chat_id, user_id)
+        KickChatMember::new(self, chat_id, user_id)
     }
 
     pub fn pin_chat_message<C, M>(
@@ -149,7 +160,7 @@ impl Bot {
         C: Into<ChatId>,
         M: Into<i32>,
     {
-        PinChatMessage::new(self.ctx(), chat_id, message_id)
+        PinChatMessage::new(self, chat_id, message_id)
     }
 
     pub fn promote_chat_member<C, U>(
@@ -161,7 +172,7 @@ impl Bot {
         C: Into<ChatId>,
         U: Into<i32>,
     {
-        PromoteChatMember::new(self.ctx(), chat_id, user_id)
+        PromoteChatMember::new(self, chat_id, user_id)
     }
 
     pub fn restrict_chat_member<C, U, P>(
@@ -175,7 +186,7 @@ impl Bot {
         U: Into<i32>,
         P: Into<ChatPermissions>,
     {
-        RestrictChatMember::new(self.ctx(), chat_id, user_id, permissions)
+        RestrictChatMember::new(self, chat_id, user_id, permissions)
     }
 
     pub fn send_chat_action<C, A>(
@@ -187,7 +198,7 @@ impl Bot {
         C: Into<ChatId>,
         A: Into<ChatAction>,
     {
-        SendChatAction::new(self.ctx(), chat_id, action)
+        SendChatAction::new(self, chat_id, action)
     }
 
     pub fn send_contact<C, P, F>(
@@ -201,7 +212,7 @@ impl Bot {
         P: Into<String>,
         F: Into<String>,
     {
-        SendContact::new(self.ctx(), chat_id, phone_number, first_name)
+        SendContact::new(self, chat_id, phone_number, first_name)
     }
 
     pub fn send_poll<C, Q, O>(
@@ -215,7 +226,7 @@ impl Bot {
         Q: Into<String>,
         O: Into<Vec<String>>,
     {
-        SendPoll::new(self.ctx(), chat_id, question, options)
+        SendPoll::new(self, chat_id, question, options)
     }
 
     pub fn send_venue<C, Lt, Lg, T, A>(
@@ -233,7 +244,7 @@ impl Bot {
         T: Into<String>,
         A: Into<String>,
     {
-        SendVenue::new(self.ctx(), chat_id, latitude, longitude, title, address)
+        SendVenue::new(self, chat_id, latitude, longitude, title, address)
     }
 
     pub fn send_video_note<C, V>(
@@ -243,17 +254,24 @@ impl Bot {
     ) -> SendVideoNote
     where
         C: Into<ChatId>,
-        V: Into<String>, // TODO: InputFile
+        V: Into<InputFile>,
     {
-        SendVideoNote::new(self.ctx(), chat_id, video_note)
+        SendVideoNote::new(self, chat_id, video_note)
     }
 
     pub fn send_voice<C, V>(&self, chat_id: C, voice: V) -> SendVoice
     where
         C: Into<ChatId>,
-        V: Into<String>, // TODO: InputFile
+        V: Into<InputFile>,
     {
-        SendVoice::new(self.ctx(), chat_id, voice)
+        SendVoice::new(self, chat_id, voice)
+    }
+
+    pub fn send_chat_description<C>(&self, chat_id: C) -> SetChatDescription
+    where
+        C: Into<ChatId>,
+    {
+        SetChatDescription::new(self, chat_id)
     }
 
     pub fn unban_chat_member<C, U>(
@@ -265,13 +283,144 @@ impl Bot {
         C: Into<ChatId>,
         U: Into<i32>,
     {
-        UnbanChatMember::new(self.ctx(), chat_id, user_id)
+        UnbanChatMember::new(self, chat_id, user_id)
     }
 
     pub fn unpin_chat_message<C>(&self, chat_id: C) -> UnpinChatMessage
     where
         C: Into<ChatId>,
     {
-        UnpinChatMessage::new(self.ctx(), chat_id)
+        UnpinChatMessage::new(self, chat_id)
+    }
+
+    pub fn answer_callback_query<S>(
+        &self,
+        callback_query_id: S,
+    ) -> AnswerCallbackQuery
+    where
+        S: Into<String>,
+    {
+        AnswerCallbackQuery::new(self, callback_query_id)
+    }
+
+    pub fn delete_chat_sticker_set<C>(&self, chat_id: C) -> DeleteChatStickerSet
+    where
+        C: Into<ChatId>,
+    {
+        DeleteChatStickerSet::new(self, chat_id)
+    }
+
+    pub fn set_chat_sticker_set<C, S>(
+        &self,
+        chat_id: C,
+        sticker_set_name: S,
+    ) -> SetChatStickerSet
+    where
+        C: Into<ChatId>,
+        S: Into<String>,
+    {
+        SetChatStickerSet::new(self, chat_id, sticker_set_name)
+    }
+
+    pub fn get_chat_member<C, I>(&self, chat_id: C, user_id: I) -> GetChatMember
+    where
+        C: Into<ChatId>,
+        I: Into<i32>,
+    {
+        GetChatMember::new(self, chat_id, user_id)
+    }
+
+    pub fn get_chat_administrators<C, I>(
+        &self,
+        chat_id: C,
+    ) -> GetChatAdministrators
+    where
+        C: Into<ChatId>,
+    {
+        GetChatAdministrators::new(self, chat_id)
+    }
+
+    pub fn get_chat_members_count<C>(&self, chat_id: C) -> GetChatMembersCount
+    where
+        C: Into<ChatId>,
+    {
+        GetChatMembersCount::new(self, chat_id)
+    }
+
+    pub fn send_video<C, V>(&self, chat_id: C, video: V) -> SendVideo
+    where
+        C: Into<ChatId>,
+        V: Into<InputFile>,
+    {
+        SendVideo::new(self, chat_id, video)
+    }
+
+    pub fn send_document<C, D>(&self, chat_id: C, document: D) -> SendDocument
+    where
+        C: Into<ChatId>,
+        D: Into<InputFile>,
+    {
+        SendDocument::new(self, chat_id, document)
+    }
+
+    pub fn send_animation<C, S>(
+        &self,
+        chat_id: C,
+        animation: S,
+    ) -> SendAnimation
+    where
+        C: Into<ChatId>,
+        S: Into<InputFile>,
+    {
+        SendAnimation::new(self, chat_id, animation)
+    }
+
+    pub fn set_chat_title<C, T>(&self, chat_id: C, title: T) -> SetChatTitle
+    where
+        C: Into<ChatId>,
+        T: Into<String>,
+    {
+        SetChatTitle::new(self, chat_id, title)
+    }
+
+    pub fn delete_chat_photo<C>(&self, chat_id: C) -> DeleteChatPhoto
+    where
+        C: Into<ChatId>,
+    {
+        DeleteChatPhoto::new(self, chat_id)
+    }
+
+    pub fn leave_chat<C>(&self, chat_id: C) -> LeaveChat
+    where
+        C: Into<ChatId>,
+    {
+        LeaveChat::new(self, chat_id)
+    }
+
+    pub fn set_chat_photo<C, P>(&self, chat_id: C, photo: P) -> SetChatPhoto
+    where
+        C: Into<ChatId>,
+        P: Into<InputFile>,
+    {
+        SetChatPhoto::new(self, chat_id, photo)
+    }
+
+    pub fn export_chat_invite_link<C>(&self, chat_id: C) -> ExportCharInviteLink
+    where
+        C: Into<ChatId>,
+    {
+        ExportCharInviteLink::new(self, chat_id)
+    }
+
+    pub fn set_chat_permissions<C, CP>(
+        &self,
+        chat_id: C,
+        permissions: CP,
+    ) -> SetChatPermissions
+    where
+        C: Into<ChatId>,
+        CP: Into<ChatPermissions>,
+    {
+        SetChatPermissions::new(self, chat_id, permissions)
     }
 }
diff --git a/src/bot/download.rs b/src/bot/download.rs
index d711f151..abb2da78 100644
--- a/src/bot/download.rs
+++ b/src/bot/download.rs
@@ -8,7 +8,7 @@ use crate::network::download_file_stream;
 use crate::{bot::Bot, network::download_file, DownloadError};
 
 impl Bot {
-    /// Download file from telegram into `destination`.
+    /// Download a file from Telegram into `destination`.
     /// `path` can be obtained from [`get_file`] method.
     ///
     /// For downloading as Stream of Chunks see [`download_file_stream`].
@@ -16,11 +16,10 @@ impl Bot {
     /// ## Examples
     ///
     /// ```no_run
-    /// use async_telegram_bot::{
-    ///     bot::Bot, requests::Request, types::File as TgFile,
-    /// };
+    /// use telebofr::types::File as TgFile;
     /// use tokio::fs::File;
-    /// # use async_telegram_bot::RequestError;
+    /// # use telebofr::RequestError;
+    /// use telebofr::Bot;
     ///
     /// # async fn run() -> Result<(), Box<dyn std::error::Error>> {
     /// let bot = Bot::new("TOKEN");
@@ -44,9 +43,9 @@ impl Bot {
         download_file(&self.client, &self.token, path, destination).await
     }
 
-    /// Download file from telegram.
+    /// Download a file from Telegram.
     ///
-    /// `path` can be obtained from [`get_file`] method.
+    /// `path` can be obtained from the [`get_file`] method.
     ///
     /// For downloading into [`AsyncWrite`] (e.g. [`tokio::fs::File`])
     /// see  [`download_file`].
diff --git a/src/bot/mod.rs b/src/bot/mod.rs
index 34020623..f2b45f51 100644
--- a/src/bot/mod.rs
+++ b/src/bot/mod.rs
@@ -1,39 +1,45 @@
-//! A Telegram bot.
-
 use reqwest::Client;
 
-use crate::requests::RequestContext;
-
 mod api;
 mod download;
 
+/// A Telegram bot used to build requests.
+#[derive(Debug, Clone)]
 pub struct Bot {
     token: String,
     client: Client,
 }
 
-/// Constructors
 impl Bot {
-    pub fn new(token: &str) -> Self {
+    pub fn new<S>(token: S) -> Self
+    where
+        S: Into<String>,
+    {
         Bot {
-            token: String::from(token),
+            token: token.into(),
             client: Client::new(),
         }
     }
 
-    pub fn with_client(token: &str, client: Client) -> Self {
+    pub fn with_client<S>(token: S, client: Client) -> Self
+    where
+        S: Into<String>,
+    {
         Bot {
-            token: String::from(token),
+            token: token.into(),
             client,
         }
     }
 }
 
 impl Bot {
-    fn ctx(&self) -> RequestContext {
-        RequestContext {
-            token: &self.token,
-            client: &self.client,
-        }
+    #[inline]
+    pub fn token(&self) -> &str {
+        &self.token
+    }
+
+    #[inline]
+    pub fn client(&self) -> &Client {
+        &self.client
     }
 }
diff --git a/src/dispatcher/mod.rs b/src/dispatcher/mod.rs
deleted file mode 100644
index b957411a..00000000
--- a/src/dispatcher/mod.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//! Update dispatching.
-
-pub mod filter;
-pub mod handler;
-pub mod simple;
-pub mod updater;
-
-pub use filter::Filter;
-pub use handler::Handler;
diff --git a/src/dispatcher/simple/mod.rs b/src/dispatcher/simple/mod.rs
deleted file mode 100644
index 63ce3a28..00000000
--- a/src/dispatcher/simple/mod.rs
+++ /dev/null
@@ -1,304 +0,0 @@
-pub mod error_policy;
-
-use crate::{
-    dispatcher::{
-        filter::Filter,
-        handler::Handler,
-        updater::Updater,
-    },
-    types::{
-        Update,
-        Message,
-        UpdateKind,
-        CallbackQuery,
-        ChosenInlineResult,
-    },
-};
-
-use futures::StreamExt;
-use crate::dispatcher::simple::error_policy::ErrorPolicy;
-
-
-type Handlers<'a, T, E> = Vec<(Box<dyn Filter<T> + 'a>, Box<dyn Handler<'a, T, E> + 'a>)>;
-
-/// Dispatcher that dispatches updates from telegram.
-///
-/// This is 'simple' implementation with following limitations:
-/// - Error (`E` generic parameter) _must_ implement [`std::fmt::Debug`]
-/// - All 'handlers' are boxed
-/// - Handler's fututres are also boxed
-/// - [Custom error policy] is also boxed
-/// - All errors from [updater] are ignored (TODO: remove this limitation)
-/// - All handlers executed in order (this means that in dispatcher have
-///   2 upadtes it will first execute some handler into complition with
-///   first update and **then** search for handler for second update,
-///   this is probably wrong)
-///
-/// ## Examples
-///
-/// Simplest example:
-/// ```no_run
-/// # async fn run() {
-/// use std::convert::Infallible;
-/// use async_telegram_bot::{
-///     bot::Bot,
-///     types::Message,
-///     dispatcher::{
-///         updater::polling,
-///         simple::{Dispatcher, error_policy::ErrorPolicy},
-///     },
-/// };
-///
-/// async fn handle_edited_message(mes: Message) {
-///     println!("Edited message: {:?}", mes)
-/// }
-///
-/// let bot = Bot::new("TOKEN");
-///
-/// // create dispatcher which handlers can't fail
-/// // with error policy that just ignores all errors (that can't ever happen)
-/// let mut dp = Dispatcher::<Infallible>::new(ErrorPolicy::Ignore)
-///     // Add 'handler' that will handle all messages sent to the bot
-///     .message_handler(true, |mes: Message| async move {
-///         println!("New message: {:?}", mes)
-///     })
-///     // Add 'handler' that will handle all
-///     // messages edited in chat with the bot
-///     .edited_message_handler(true, handle_edited_message);
-///
-/// // Start dispatching updates from long polling
-/// dp.dispatch(polling(&bot)).await;
-/// # }
-/// ```
-///
-/// [`std::fmt::Debug`]: std::fmt::Debug
-/// [Custom error policy]: crate::dispatcher::simple::error_policy::ErrorPolicy::Custom
-/// [updater]: crate::dispatcher::updater
-pub struct Dispatcher<'a, E> {
-    message_handlers: Handlers<'a, Message, E>,
-    edited_message_handlers: Handlers<'a, Message, E>,
-    channel_post_handlers: Handlers<'a, Message, E>,
-    edited_channel_post_handlers: Handlers<'a, Message, E>,
-    inline_query_handlers: Handlers<'a, (), E>,
-    chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, E>,
-    callback_query_handlers: Handlers<'a, CallbackQuery, E>,
-    error_policy: ErrorPolicy<'a, E>,
-}
-
-impl<'a, E> Dispatcher<'a, E>
-where
-    E: std::fmt::Debug, // TODO: Is this really necessary?
-{
-    pub fn new(error_policy: ErrorPolicy<'a, E>) -> Self {
-        Dispatcher {
-            message_handlers: Vec::new(),
-            edited_message_handlers: Vec::new(),
-            channel_post_handlers: Vec::new(),
-            edited_channel_post_handlers: Vec::new(),
-            inline_query_handlers: Vec::new(),
-            chosen_inline_result_handlers: Vec::new(),
-            callback_query_handlers: Vec::new(),
-            error_policy
-        }
-    }
-
-    pub fn message_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<Message> + 'a,
-        H: Handler<'a, Message, E> + 'a,
-    {
-        self.message_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    pub fn edited_message_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<Message> + 'a,
-        H: Handler<'a, Message, E> + 'a,
-    {
-        self.edited_message_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    pub fn channel_post_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<Message> + 'a,
-        H: Handler<'a, Message, E> + 'a,
-    {
-        self.channel_post_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    pub fn edited_channel_post_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<Message> + 'a,
-        H: Handler<'a, Message, E> + 'a,
-    {
-        self.edited_channel_post_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    pub fn inline_query_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<()> + 'a,
-        H: Handler<'a, (), E> + 'a,
-    {
-        self.inline_query_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    pub fn chosen_inline_result_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<ChosenInlineResult> + 'a,
-        H: Handler<'a, ChosenInlineResult, E> + 'a,
-    {
-        self.chosen_inline_result_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    pub fn callback_query_handler<F, H>(mut self, filter: F, handler: H) -> Self
-    where
-        F: Filter<CallbackQuery> + 'a,
-        H: Handler<'a, CallbackQuery, E> + 'a,
-    {
-        self.callback_query_handlers.push((Box::new(filter), Box::new(handler)));
-        self
-    }
-
-    // TODO: Can someone simplify this?
-    pub async fn dispatch<U, UE>(&mut self, updates: U)
-    where
-        U: Updater<UE> + 'a
-    {
-        updates.for_each(|res| {
-            async {
-                let res = res;
-                let Update { kind, id } = match res {
-                    Ok(upd) => upd,
-                    _ => return // TODO: proper error handling
-                };
-
-                log::debug!("Handled update#{id:?}: {kind:?}", id = id, kind = kind);
-
-                // TODO: can someone extract this to a function?
-                macro_rules! call {
-                    ($h:expr, $value:expr) => {{
-                        let value = $value;
-                        let handler = $h.iter().find_map(|e| {
-                            let (filter, handler) = e;
-                            if filter.test(&value) {
-                                Some(handler)
-                            } else {
-                                None
-                            }
-                        });
-
-                        match handler {
-                            Some(handler) => {
-                                 if let Err(err) = handler.handle(value).await {
-                                    self.error_policy.handle_error(err).await;
-                                 }
-                            },
-                            None => log::warn!("Unhandled update: {:?}", value)
-                        }
-                    }};
-                }
-
-                match kind {
-                    UpdateKind::Message(mes) => call!(self.message_handlers, mes),
-                    UpdateKind::EditedMessage(mes) => call!(self.edited_message_handlers, mes),
-                    UpdateKind::ChannelPost(post) => call!(self.channel_post_handlers, post),
-                    UpdateKind::EditedChannelPost(post) => call!(self.edited_channel_post_handlers, post),
-                    UpdateKind::InlineQuery(query) => call!(self.inline_query_handlers, query),
-                    UpdateKind::ChosenInlineResult(result) => call!(self.chosen_inline_result_handlers, result),
-                    UpdateKind::CallbackQuery(callback) => call!(self.callback_query_handlers, callback),
-                }
-            }
-        })
-            .await;
-    }
-}
-
-
-#[cfg(test)]
-mod tests {
-    use std::convert::Infallible;
-    use std::sync::atomic::{AtomicI32, Ordering};
-
-    use crate::{
-        types::{
-            Message, ChatKind, MessageKind, Sender, ForwardKind, MediaKind, Chat, User, Update, UpdateKind
-        },
-        dispatcher::{simple::{Dispatcher, error_policy::ErrorPolicy}, updater::StreamUpdater},
-    };
-    use futures::Stream;
-
-    #[tokio::test]
-    async fn first_handler_executes_1_time() {
-        let counter = &AtomicI32::new(0);
-        let counter2 = &AtomicI32::new(0);
-
-        let mut dp = Dispatcher::<Infallible>::new(ErrorPolicy::Ignore)
-            .message_handler(true, |_mes: Message| async move {
-                counter.fetch_add(1, Ordering::SeqCst);
-            })
-            .message_handler(true, |_mes: Message| async move {
-                counter2.fetch_add(1, Ordering::SeqCst);
-                Ok::<_, Infallible>(())
-            });
-
-        dp.dispatch(one_message_updater()).await;
-
-        assert_eq!(counter.load(Ordering::SeqCst), 1);
-        assert_eq!(counter2.load(Ordering::SeqCst), 0);
-    }
-
-    fn message() -> Message {
-        Message {
-            id: 6534,
-            date: 1567898953,
-            chat: Chat {
-                id: 218485655,
-                photo: None,
-                kind: ChatKind::Private {
-                    type_: (),
-                    first_name: Some("W".to_string()),
-                    last_name: None,
-                    username: Some("WaffleLapkin".to_string()),
-                },
-            },
-            kind: MessageKind::Common {
-                from: Sender::User(User {
-                    id: 457569668,
-                    is_bot: true,
-                    first_name: "BT".to_string(),
-                    last_name: None,
-                    username: Some("BloodyTestBot".to_string()),
-                    language_code: None,
-                }),
-                forward_kind: ForwardKind::Origin {
-                    reply_to_message: None,
-                },
-                edit_date: None,
-                media_kind: MediaKind::Text {
-                    text: "text".to_string(),
-                    entities: vec![],
-                },
-                reply_markup: None,
-            },
-        }
-    }
-
-    fn message_update() -> Update {
-        Update { id: 0, kind: UpdateKind::Message(message()) }
-    }
-
-    fn one_message_updater() -> StreamUpdater<impl Stream<Item=Result<Update, Infallible>>> {
-        use futures::future::ready;
-        use futures::stream;
-
-        StreamUpdater::new(
-            stream::once(ready(Ok(message_update())))
-        )
-    }
-}
diff --git a/src/dispatcher/simple/error_policy.rs b/src/dispatching/dispatchers/filter/error_policy.rs
similarity index 77%
rename from src/dispatcher/simple/error_policy.rs
rename to src/dispatching/dispatchers/filter/error_policy.rs
index d71b254b..8e922c63 100644
--- a/src/dispatcher/simple/error_policy.rs
+++ b/src/dispatching/dispatchers/filter/error_policy.rs
@@ -1,6 +1,4 @@
-use std::pin::Pin;
-use std::future::Future;
-use std::fmt::Debug;
+use std::{fmt::Debug, future::Future, pin::Pin};
 
 // TODO: shouldn't it be trait?
 pub enum ErrorPolicy<'a, E> {
@@ -15,14 +13,12 @@ where
 {
     pub async fn handle_error(&self, error: E) {
         match self {
-            Self::Ignore => {},
+            Self::Ignore => {}
             Self::Log => {
                 // TODO: better message
                 log::error!("Error in handler: {:?}", error)
             }
-            Self::Custom(func) => {
-                func(error).await
-            }
+            Self::Custom(func) => func(error).await,
         }
     }
 
@@ -33,4 +29,4 @@ where
     {
         Self::Custom(Box::new(move |e| Box::pin(f(e))))
     }
-}
\ No newline at end of file
+}
diff --git a/src/dispatching/dispatchers/filter/mod.rs b/src/dispatching/dispatchers/filter/mod.rs
new file mode 100644
index 00000000..b3ed259f
--- /dev/null
+++ b/src/dispatching/dispatchers/filter/mod.rs
@@ -0,0 +1,373 @@
+use futures::StreamExt;
+
+use async_trait::async_trait;
+
+use crate::{
+    dispatching::{
+        dispatchers::filter::error_policy::ErrorPolicy, filters::Filter,
+        handler::Handler, updater::Updater, Dispatcher,
+    },
+    types::{CallbackQuery, ChosenInlineResult, Message, Update, UpdateKind},
+};
+
+pub mod error_policy;
+
+type Handlers<'a, T, E> =
+    Vec<(Box<dyn Filter<T> + 'a>, Box<dyn Handler<'a, T, E> + 'a>)>;
+
+/// Dispatcher that dispatches updates from telegram.
+///
+/// This is 'filter' implementation with following limitations:
+/// - Error (`E` generic parameter) _must_ implement [`std::fmt::Debug`]
+/// - All 'handlers' are boxed
+/// - Handler's fututres are also boxed
+/// - [Custom error policy] is also boxed
+/// - All errors from [updater] are ignored (TODO: remove this limitation)
+/// - All handlers executed in order (this means that in dispatching have 2
+///   upadtes it will first execute some handler into complition with first
+///   update and **then** search for handler for second update, this is probably
+///   wrong)
+///
+/// ## Examples
+///
+/// Simplest example:
+/// ```no_run
+/// # use telebofr::Bot;
+/// use telebofr::types::Message;
+///  async fn run() {
+/// use std::convert::Infallible;
+/// use telebofr::{
+///     dispatching::{
+///         dispatchers::filter::{error_policy::ErrorPolicy, FilterDispatcher},
+///         updater::polling,
+///     },
+/// };
+///
+/// async fn handle_edited_message(mes: Message) {
+///     println!("Edited message: {:?}", mes)
+/// }
+///
+/// let bot = Bot::new("TOKEN");
+///
+/// // create dispatching which handlers can't fail
+/// // with error policy that just ignores all errors (that can't ever happen)
+/// let mut dp = FilterDispatcher::<Infallible>::new(ErrorPolicy::Ignore)
+///     // Add 'handler' that will handle all messages sent to the bot
+///     .message_handler(true, |mes: Message| {
+///         async move { println!("New message: {:?}", mes) }
+///     })
+///     // Add 'handler' that will handle all
+///     // messages edited in chat with the bot
+///     .edited_message_handler(true, handle_edited_message);
+///
+/// // Start dispatching updates from long polling
+/// dp.dispatch(polling(&bot)).await;
+/// # }
+/// ```
+///
+/// [`std::fmt::Debug`]: std::fmt::Debug
+/// [Custom error policy]:
+/// crate::dispatching::filter::error_policy::ErrorPolicy::Custom [updater]:
+/// crate::dispatching::updater
+pub struct FilterDispatcher<'a, E> {
+    message_handlers: Handlers<'a, Message, E>,
+    edited_message_handlers: Handlers<'a, Message, E>,
+    channel_post_handlers: Handlers<'a, Message, E>,
+    edited_channel_post_handlers: Handlers<'a, Message, E>,
+    inline_query_handlers: Handlers<'a, (), E>,
+    chosen_inline_result_handlers: Handlers<'a, ChosenInlineResult, E>,
+    callback_query_handlers: Handlers<'a, CallbackQuery, E>,
+    error_policy: ErrorPolicy<'a, E>,
+}
+
+impl<'a, E> FilterDispatcher<'a, E>
+where
+    E: std::fmt::Debug, // TODO: Is this really necessary?
+{
+    pub fn new(error_policy: ErrorPolicy<'a, E>) -> Self {
+        FilterDispatcher {
+            message_handlers: Vec::new(),
+            edited_message_handlers: Vec::new(),
+            channel_post_handlers: Vec::new(),
+            edited_channel_post_handlers: Vec::new(),
+            inline_query_handlers: Vec::new(),
+            chosen_inline_result_handlers: Vec::new(),
+            callback_query_handlers: Vec::new(),
+            error_policy,
+        }
+    }
+
+    pub fn message_handler<F, H>(mut self, filter: F, handler: H) -> Self
+    where
+        F: Filter<Message> + 'a,
+        H: Handler<'a, Message, E> + 'a,
+    {
+        self.message_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    pub fn edited_message_handler<F, H>(mut self, filter: F, handler: H) -> Self
+    where
+        F: Filter<Message> + 'a,
+        H: Handler<'a, Message, E> + 'a,
+    {
+        self.edited_message_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    pub fn channel_post_handler<F, H>(mut self, filter: F, handler: H) -> Self
+    where
+        F: Filter<Message> + 'a,
+        H: Handler<'a, Message, E> + 'a,
+    {
+        self.channel_post_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    pub fn edited_channel_post_handler<F, H>(
+        mut self,
+        filter: F,
+        handler: H,
+    ) -> Self
+    where
+        F: Filter<Message> + 'a,
+        H: Handler<'a, Message, E> + 'a,
+    {
+        self.edited_channel_post_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    pub fn inline_query_handler<F, H>(mut self, filter: F, handler: H) -> Self
+    where
+        F: Filter<()> + 'a,
+        H: Handler<'a, (), E> + 'a,
+    {
+        self.inline_query_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    pub fn chosen_inline_result_handler<F, H>(
+        mut self,
+        filter: F,
+        handler: H,
+    ) -> Self
+    where
+        F: Filter<ChosenInlineResult> + 'a,
+        H: Handler<'a, ChosenInlineResult, E> + 'a,
+    {
+        self.chosen_inline_result_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    pub fn callback_query_handler<F, H>(mut self, filter: F, handler: H) -> Self
+    where
+        F: Filter<CallbackQuery> + 'a,
+        H: Handler<'a, CallbackQuery, E> + 'a,
+    {
+        self.callback_query_handlers
+            .push((Box::new(filter), Box::new(handler)));
+        self
+    }
+
+    // TODO: Can someone simplify this?
+    pub async fn dispatch<U>(&mut self, updates: U)
+    where
+        U: Updater + 'a,
+    {
+        updates
+            .for_each(|res| {
+                async {
+                    let res = res;
+                    let Update { kind, id } = match res {
+                        Ok(upd) => upd,
+                        _ => return, // TODO: proper error handling
+                    };
+
+                    log::debug!(
+                        "Handled update#{id:?}: {kind:?}",
+                        id = id,
+                        kind = kind
+                    );
+
+                    match kind {
+                        UpdateKind::Message(mes) => {
+                            self.handle(mes, &self.message_handlers).await
+                        }
+                        UpdateKind::EditedMessage(mes) => {
+                            self.handle(mes, &self.edited_message_handlers)
+                                .await;
+                        }
+                        UpdateKind::ChannelPost(post) => {
+                            self.handle(post, &self.channel_post_handlers)
+                                .await;
+                        }
+                        UpdateKind::EditedChannelPost(post) => {
+                            self.handle(
+                                post,
+                                &self.edited_channel_post_handlers,
+                            )
+                            .await;
+                        }
+                        UpdateKind::InlineQuery(query) => {
+                            self.handle(query, &self.inline_query_handlers)
+                                .await;
+                        }
+                        UpdateKind::ChosenInlineResult(result) => {
+                            self.handle(
+                                result,
+                                &self.chosen_inline_result_handlers,
+                            )
+                            .await;
+                        }
+                        UpdateKind::CallbackQuery(callback) => {
+                            self.handle(
+                                callback,
+                                &self.callback_query_handlers,
+                            )
+                            .await;
+                        }
+                    }
+                }
+            })
+            .await;
+    }
+
+    async fn handle<T>(&self, update: T, handlers: &Handlers<'a, T, E>)
+    where
+        T: std::fmt::Debug,
+    {
+        let handler = handlers.iter().find_map(|e| {
+            let (filter, handler) = e;
+            if filter.test(&update) {
+                Some(handler)
+            } else {
+                None
+            }
+        });
+
+        match handler {
+            Some(handler) => {
+                if let Err(err) = handler.handle(update).await {
+                    self.error_policy.handle_error(err).await
+                }
+            }
+            None => {
+                log::warn!("unhandled update {:?}", update);
+            }
+        }
+    }
+}
+
+#[async_trait(? Send)]
+impl<'a, U, E> Dispatcher<'a, U> for FilterDispatcher<'a, E>
+where
+    E: std::fmt::Debug,
+    U: Updater + 'a,
+{
+    async fn dispatch(&'a mut self, updater: U) {
+        FilterDispatcher::dispatch(self, updater).await
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::{
+        convert::Infallible,
+        sync::atomic::{AtomicI32, Ordering},
+    };
+
+    use futures::Stream;
+
+    use crate::{
+        dispatching::{
+            dispatchers::filter::{
+                error_policy::ErrorPolicy, FilterDispatcher,
+            },
+            updater::StreamUpdater,
+        },
+        types::{
+            Chat, ChatKind, ForwardKind, MediaKind, Message, MessageKind,
+            Sender, Update, UpdateKind, User,
+        },
+    };
+
+    #[tokio::test]
+    async fn first_handler_executes_1_time() {
+        let counter = &AtomicI32::new(0);
+        let counter2 = &AtomicI32::new(0);
+
+        let mut dp = FilterDispatcher::<Infallible>::new(ErrorPolicy::Ignore)
+            .message_handler(true, |_mes: Message| {
+                async move {
+                    counter.fetch_add(1, Ordering::SeqCst);
+                }
+            })
+            .message_handler(true, |_mes: Message| {
+                async move {
+                    counter2.fetch_add(1, Ordering::SeqCst);
+                    Ok::<_, Infallible>(())
+                }
+            });
+
+        dp.dispatch(one_message_updater()).await;
+
+        assert_eq!(counter.load(Ordering::SeqCst), 1);
+        assert_eq!(counter2.load(Ordering::SeqCst), 0);
+    }
+
+    fn message() -> Message {
+        Message {
+            id: 6534,
+            date: 1567898953,
+            chat: Chat {
+                id: 218485655,
+                photo: None,
+                kind: ChatKind::Private {
+                    type_: (),
+                    first_name: Some("W".to_string()),
+                    last_name: None,
+                    username: Some("WaffleLapkin".to_string()),
+                },
+            },
+            kind: MessageKind::Common {
+                from: Sender::User(User {
+                    id: 457569668,
+                    is_bot: true,
+                    first_name: "BT".to_string(),
+                    last_name: None,
+                    username: Some("BloodyTestBot".to_string()),
+                    language_code: None,
+                }),
+                forward_kind: ForwardKind::Origin {
+                    reply_to_message: None,
+                },
+                edit_date: None,
+                media_kind: MediaKind::Text {
+                    text: "text".to_string(),
+                    entities: vec![],
+                },
+                reply_markup: None,
+            },
+        }
+    }
+
+    fn message_update() -> Update {
+        Update {
+            id: 0,
+            kind: UpdateKind::Message(message()),
+        }
+    }
+
+    fn one_message_updater(
+    ) -> StreamUpdater<impl Stream<Item = Result<Update, Infallible>>> {
+        use futures::{future::ready, stream};
+
+        StreamUpdater::new(stream::once(ready(Ok(message_update()))))
+    }
+}
diff --git a/src/dispatching/dispatchers/mod.rs b/src/dispatching/dispatchers/mod.rs
new file mode 100644
index 00000000..1ec549e1
--- /dev/null
+++ b/src/dispatching/dispatchers/mod.rs
@@ -0,0 +1,3 @@
+pub use filter::FilterDispatcher;
+
+pub mod filter;
diff --git a/src/dispatching/filters/command.rs b/src/dispatching/filters/command.rs
new file mode 100644
index 00000000..b807050a
--- /dev/null
+++ b/src/dispatching/filters/command.rs
@@ -0,0 +1,110 @@
+use crate::{dispatching::Filter, types::Message};
+
+pub struct CommandFilter {
+    command: String,
+}
+
+impl Filter<Message> for CommandFilter {
+    fn test(&self, value: &Message) -> bool {
+        match value.text() {
+            Some(text) => match text.split_whitespace().next() {
+                Some(command) => self.command == command,
+                None => false,
+            },
+            None => false,
+        }
+    }
+}
+
+impl CommandFilter {
+    pub fn new<T>(command: T) -> Self
+    where
+        T: Into<String>,
+    {
+        Self {
+            command: '/'.to_string() + &command.into(),
+        }
+    }
+    pub fn with_prefix<T>(command: T, prefix: T) -> Self
+    where
+        T: Into<String>,
+    {
+        Self {
+            command: prefix.into() + &command.into(),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::types::{
+        Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User,
+    };
+
+    #[test]
+    fn commands_are_equal() {
+        let filter = CommandFilter::new("command".to_string());
+        let message = create_message_with_text("/command".to_string());
+        assert!(filter.test(&message));
+    }
+
+    #[test]
+    fn commands_are_not_equal() {
+        let filter = CommandFilter::new("command".to_string());
+        let message =
+            create_message_with_text("/not_equal_command".to_string());
+        assert_eq!(filter.test(&message), false);
+    }
+
+    #[test]
+    fn command_have_args() {
+        let filter = CommandFilter::new("command".to_string());
+        let message =
+            create_message_with_text("/command arg1 arg2".to_string());
+        assert!(filter.test(&message));
+    }
+
+    #[test]
+    fn message_have_only_whitespace() {
+        let filter = CommandFilter::new("command".to_string());
+        let message = create_message_with_text(" ".to_string());
+        assert_eq!(filter.test(&message), false);
+    }
+
+    fn create_message_with_text(text: String) -> Message {
+        Message {
+            id: 0,
+            date: 0,
+            chat: Chat {
+                id: 0,
+                kind: ChatKind::Private {
+                    type_: (),
+                    username: None,
+                    first_name: None,
+                    last_name: None,
+                },
+                photo: None,
+            },
+            kind: MessageKind::Common {
+                from: Sender::User(User {
+                    id: 0,
+                    is_bot: false,
+                    first_name: "".to_string(),
+                    last_name: None,
+                    username: None,
+                    language_code: None,
+                }),
+                forward_kind: ForwardKind::Origin {
+                    reply_to_message: None,
+                },
+                edit_date: None,
+                media_kind: MediaKind::Text {
+                    text,
+                    entities: vec![],
+                },
+                reply_markup: None,
+            },
+        }
+    }
+}
diff --git a/src/dispatcher/filter.rs b/src/dispatching/filters/main.rs
similarity index 80%
rename from src/dispatcher/filter.rs
rename to src/dispatching/filters/main.rs
index e1c267ad..8c513405 100644
--- a/src/dispatcher/filter.rs
+++ b/src/dispatching/filters/main.rs
@@ -6,7 +6,7 @@ pub trait Filter<T> {
 }
 
 /// ```
-/// use async_telegram_bot::dispatcher::filter::Filter;
+/// use telebofr::dispatching::filters::Filter;
 ///
 /// let closure = |i: &i32| -> bool { *i >= 42 };
 /// assert!(closure.test(&42));
@@ -22,13 +22,15 @@ impl<T, F: Fn(&T) -> bool> Filter<T> for F {
 }
 
 /// ```
-/// use async_telegram_bot::dispatcher::filter::Filter;
+/// use telebofr::dispatching::filters::Filter;
 ///
 /// assert!(true.test(&()));
 /// assert_eq!(false.test(&()), false);
 /// ```
 impl<T> Filter<T> for bool {
-    fn test(&self, _: &T) -> bool { *self }
+    fn test(&self, _: &T) -> bool {
+        *self
+    }
 }
 
 /// And filter.
@@ -40,7 +42,7 @@ impl<T> Filter<T> for bool {
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{And, Filter};
+/// use telebofr::dispatching::filters::{And, Filter};
 ///
 /// // Note: bool can be treated as `Filter` that always return self.
 /// assert_eq!(And::new(true, false).test(&()), false);
@@ -71,18 +73,17 @@ where
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{and, Filter};
+/// use telebofr::dispatching::filters::{and, Filter};
 ///
 /// assert!(and(true, true).test(&()));
 /// assert_eq!(and(true, false).test(&()), false);
 /// ```
 ///
-/// [`And::new`]: crate::dispatcher::filter::And::new
+/// [`And::new`]: crate::dispatching::filter::And::new
 pub fn and<A, B>(a: A, b: B) -> And<A, B> {
     And::new(a, b)
 }
 
-
 /// Or filter.
 ///
 /// Passes if at least one underlying filters passes.
@@ -92,7 +93,7 @@ pub fn and<A, B>(a: A, b: B) -> And<A, B> {
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{Or, Filter};
+/// use telebofr::dispatching::filters::{Filter, Or};
 ///
 /// // Note: bool can be treated as `Filter` that always return self.
 /// assert!(Or::new(true, false).test(&()));
@@ -123,25 +124,24 @@ where
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{or, Filter};
+/// use telebofr::dispatching::filters::{or, Filter};
 ///
 /// assert!(or(true, false).test(&()));
 /// assert_eq!(or(false, false).test(&()), false);
 /// ```
 ///
-/// [`Or::new`]: crate::dispatcher::filter::Or::new
+/// [`Or::new`]: crate::dispatching::filter::Or::new
 pub fn or<A, B>(a: A, b: B) -> Or<A, B> {
     Or::new(a, b)
 }
 
-
 /// Not filter.
 ///
 /// Passes if underlying filter don't pass.
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{Not, Filter};
+/// use telebofr::dispatching::filters::{Filter, Not};
 ///
 /// // Note: bool can be treated as `Filter` that always return self.
 /// assert!(Not::new(false).test(&()));
@@ -169,13 +169,13 @@ where
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{not, Filter};
+/// use telebofr::dispatching::filters::{not, Filter};
 ///
 /// assert!(not(false).test(&()));
 /// assert_eq!(not(true).test(&()), false);
 /// ```
 ///
-/// [`Not::new`]: crate::dispatcher::filter::Not::new
+/// [`Not::new`]: crate::dispatching::filter::Not::new
 pub fn not<A>(a: A) -> Not<A> {
     Not::new(a)
 }
@@ -187,7 +187,7 @@ pub fn not<A>(a: A) -> Not<A> {
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::{all, dispatcher::filter::Filter};
+/// use telebofr::{all, dispatching::filters::Filter};
 ///
 /// assert!(all![true].test(&()));
 /// assert!(all![true, true].test(&()));
@@ -199,12 +199,12 @@ pub fn not<A>(a: A) -> Not<A> {
 /// assert_eq!(all![false, false].test(&()), false);
 /// ```
 ///
-/// [filter]: crate::dispatcher::filter::Filter
+/// [filter]: crate::dispatching::filter::Filter
 #[macro_export]
 macro_rules! all {
     ($one:expr) => { $one };
     ($head:expr, $($tail:tt)+) => {
-        $crate::dispatcher::filter::And::new(
+        $crate::dispatching::filters::And::new(
             $head,
             $crate::all!($($tail)+)
         )
@@ -218,7 +218,7 @@ macro_rules! all {
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::{any, dispatcher::filter::Filter};
+/// use telebofr::{any, dispatching::filters::Filter};
 ///
 /// assert!(any![true].test(&()));
 /// assert!(any![true, true].test(&()));
@@ -230,24 +230,23 @@ macro_rules! all {
 /// assert_eq!(any![false, false, false].test(&()), false);
 /// ```
 ///
-/// [filter]: crate::dispatcher::filter::Filter
+/// [filter]: crate::dispatching::filter::Filter
 #[macro_export]
 macro_rules! any {
     ($one:expr) => { $one };
     ($head:expr, $($tail:tt)+) => {
-        $crate::dispatcher::filter::Or::new(
+        $crate::dispatching::filters::Or::new(
             $head,
             $crate::all!($($tail)+)
         )
     };
 }
 
-
 /// Simple wrapper around `Filter` that adds `|` and `&` operators.
 ///
 /// ## Examples
 /// ```
-/// use async_telegram_bot::dispatcher::filter::{Filter, f, F, And, Or};
+/// use telebofr::dispatching::filters::{f, And, Filter, Or, F};
 ///
 /// let flt1 = |i: &i32| -> bool { *i > 17 };
 /// let flt2 = |i: &i32| -> bool { *i < 42 };
@@ -259,7 +258,6 @@ macro_rules! any {
 /// assert_eq!(and.test(&50), false); // `flt2` doesn't pass
 /// assert_eq!(and.test(&16), false); // `flt1` doesn't pass
 ///
-///
 /// let or = f(flt1) | flt3;
 /// assert!(or.test(&19)); // `flt1` passes
 /// assert!(or.test(&16)); // `flt2` passes
@@ -267,9 +265,8 @@ macro_rules! any {
 ///
 /// assert_eq!(or.test(&17), false); // both don't pass
 ///
-///
 /// // Note: only first filter in chain should be wrapped in `f(...)`
-/// let complicated: F<Or<And<_, _>, _>>= f(flt1) & flt2 | flt3;
+/// let complicated: F<Or<And<_, _>, _>> = f(flt1) & flt2 | flt3;
 /// assert!(complicated.test(&2)); // `flt3` passes
 /// assert!(complicated.test(&21)); // `flt1` and `flt2` pass
 ///
@@ -280,14 +277,14 @@ pub struct F<A>(A);
 
 /// Constructor fn for [F]
 ///
-/// [F]: crate::dispatcher::filter::F;
+/// [F]: crate::dispatching::filter::F;
 pub fn f<A>(a: A) -> F<A> {
     F(a)
 }
 
 impl<T, A> Filter<T> for F<A>
 where
-    A: Filter<T>
+    A: Filter<T>,
 {
     fn test(&self, value: &T) -> bool {
         self.0.test(value)
@@ -310,13 +307,14 @@ impl<A, B> std::ops::BitOr<B> for F<A> {
     }
 }
 
+/* workaround for `E0207` compiler error */
 /// Extensions for filters
-pub trait FilterExt<T /* workaround for `E0207` compiler error */> {
+pub trait FilterExt<T> {
     /// Alias for [`Not::new`]
     ///
     /// ## Examples
     /// ```
-    /// use async_telegram_bot::dispatcher::filter::{Filter, FilterExt};
+    /// use telebofr::dispatching::filters::{Filter, FilterExt};
     ///
     /// let flt = |i: &i32| -> bool { *i > 0 };
     /// let flt = flt.not();
@@ -324,8 +322,11 @@ pub trait FilterExt<T /* workaround for `E0207` compiler error */> {
     /// assert_eq!(flt.test(&1), false);
     /// ```
     ///
-    /// [`Not::new`]: crate::dispatcher::filter::Not::new
-    fn not(self) -> Not<Self> where Self: Sized {
+    /// [`Not::new`]: crate::dispatching::filter::Not::new
+    fn not(self) -> Not<Self>
+    where
+        Self: Sized,
+    {
         Not::new(self)
     }
 
@@ -333,7 +334,7 @@ pub trait FilterExt<T /* workaround for `E0207` compiler error */> {
     ///
     /// ## Examples
     /// ```
-    /// use async_telegram_bot::dispatcher::filter::{Filter, FilterExt};
+    /// use telebofr::dispatching::filters::{Filter, FilterExt};
     ///
     /// let flt = |i: &i32| -> bool { *i > 0 };
     /// let flt = flt.and(|i: &i32| *i < 42);
@@ -343,8 +344,11 @@ pub trait FilterExt<T /* workaround for `E0207` compiler error */> {
     /// assert_eq!(flt.test(&43), false);
     /// ```
     ///
-    /// [`Not::new`]: crate::dispatcher::filter::And::new
-    fn and<B>(self, other: B) -> And<Self, B> where Self: Sized {
+    /// [`Not::new`]: crate::dispatching::filter::And::new
+    fn and<B>(self, other: B) -> And<Self, B>
+    where
+        Self: Sized,
+    {
         And::new(self, other)
     }
 
@@ -352,7 +356,7 @@ pub trait FilterExt<T /* workaround for `E0207` compiler error */> {
     ///
     /// ## Examples
     /// ```
-    /// use async_telegram_bot::dispatcher::filter::{Filter, FilterExt};
+    /// use telebofr::dispatching::filters::{Filter, FilterExt};
     ///
     /// let flt = |i: &i32| -> bool { *i < 0 };
     /// let flt = flt.or(|i: &i32| *i > 42);
@@ -362,8 +366,11 @@ pub trait FilterExt<T /* workaround for `E0207` compiler error */> {
     /// assert_eq!(flt.test(&17), false);
     /// ```
     ///
-    /// [`Not::new`]: crate::dispatcher::filter::Or::new
-    fn or<B>(self, other: B) -> Or<Self, B> where Self: Sized {
+    /// [`Not::new`]: crate::dispatching::filter::Or::new
+    fn or<B>(self, other: B) -> Or<Self, B>
+    where
+        Self: Sized,
+    {
         Or::new(self, other)
     }
 }
diff --git a/src/dispatching/filters/message_caption.rs b/src/dispatching/filters/message_caption.rs
new file mode 100644
index 00000000..0539390e
--- /dev/null
+++ b/src/dispatching/filters/message_caption.rs
@@ -0,0 +1,100 @@
+use crate::{dispatching::Filter, types::Message};
+
+/// Filter which compare caption of media with another text.
+/// Returns true if the caption of media is equal to another text, otherwise
+/// false.
+///
+/// NOTE: filter compares only caption of media, does not compare text of
+/// message!
+///
+/// If you want to compare text of message use
+/// [MessageTextFilter]
+///
+/// If you want to compare text and caption use
+/// [MessageTextCaptionFilter]
+///
+/// [MessageTextFilter]: telebofr::dispatching::filters::MessageTextFilter
+/// [MessageTextCaptionFilter]:
+/// telebofr::dispatching::filters::MessageTextCaptionFilter
+pub struct MessageCaptionFilter {
+    text: String,
+}
+
+impl Filter<Message> for MessageCaptionFilter {
+    fn test(&self, value: &Message) -> bool {
+        match value.caption() {
+            Some(caption) => self.text == caption,
+            None => false,
+        }
+    }
+}
+
+impl MessageCaptionFilter {
+    pub fn new<T>(text: T) -> Self
+    where
+        T: Into<String>,
+    {
+        Self { text: text.into() }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::types::{
+        Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User,
+    };
+
+    #[test]
+    fn captions_are_equal() {
+        let filter = MessageCaptionFilter::new("caption".to_string());
+        let message = create_message_with_caption("caption".to_string());
+        assert!(filter.test(&message));
+    }
+
+    #[test]
+    fn captions_are_not_equal() {
+        let filter = MessageCaptionFilter::new("caption".to_string());
+        let message =
+            create_message_with_caption("not equal caption".to_string());
+        assert_eq!(filter.test(&message), false);
+    }
+
+    fn create_message_with_caption(caption: String) -> Message {
+        Message {
+            id: 0,
+            date: 0,
+            chat: Chat {
+                id: 0,
+                kind: ChatKind::Private {
+                    type_: (),
+                    username: None,
+                    first_name: None,
+                    last_name: None,
+                },
+                photo: None,
+            },
+            kind: MessageKind::Common {
+                from: Sender::User(User {
+                    id: 0,
+                    is_bot: false,
+                    first_name: "".to_string(),
+                    last_name: None,
+                    username: None,
+                    language_code: None,
+                }),
+                forward_kind: ForwardKind::Origin {
+                    reply_to_message: None,
+                },
+                edit_date: None,
+                media_kind: MediaKind::Photo {
+                    photo: vec![],
+                    caption: Some(caption),
+                    caption_entities: vec![],
+                    media_group_id: None,
+                },
+                reply_markup: None,
+            },
+        }
+    }
+}
diff --git a/src/dispatching/filters/message_text.rs b/src/dispatching/filters/message_text.rs
new file mode 100644
index 00000000..28db8206
--- /dev/null
+++ b/src/dispatching/filters/message_text.rs
@@ -0,0 +1,95 @@
+use crate::{dispatching::Filter, types::Message};
+
+/// Filter which compare message text with another text.
+/// Returns true if the message text is equal to another text, otherwise false.
+///
+/// NOTE: filter compares only text message, does not compare caption of media!
+///
+/// If you want to compare caption use
+/// [MessageCaptionFilter]
+///
+/// If you want to compare text and caption use
+/// [MessageTextCaptionFilter]
+///
+/// [MessageCaptionFilter]: telebofr::dispatching::filters::MessageCaptionFilter
+/// [MessageTextCaptionFilter]:
+/// telebofr::dispatching::filters::MessageTextCaptionFilter
+pub struct MessageTextFilter {
+    text: String,
+}
+
+impl Filter<Message> for MessageTextFilter {
+    fn test(&self, value: &Message) -> bool {
+        match value.text() {
+            Some(text) => self.text == text,
+            None => false,
+        }
+    }
+}
+
+impl MessageTextFilter {
+    pub fn new<T>(text: T) -> Self
+    where
+        T: Into<String>,
+    {
+        Self { text: text.into() }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::types::{
+        Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User,
+    };
+
+    #[test]
+    fn texts_are_equal() {
+        let filter = MessageTextFilter::new("text");
+        let message = create_message_with_text("text".to_string());
+        assert!(filter.test(&message));
+    }
+
+    #[test]
+    fn texts_are_not_equal() {
+        let filter = MessageTextFilter::new("text");
+        let message = create_message_with_text("not equal text".to_string());
+        assert_eq!(filter.test(&message), false);
+    }
+
+    fn create_message_with_text(text: String) -> Message {
+        Message {
+            id: 0,
+            date: 0,
+            chat: Chat {
+                id: 0,
+                kind: ChatKind::Private {
+                    type_: (),
+                    username: None,
+                    first_name: None,
+                    last_name: None,
+                },
+                photo: None,
+            },
+            kind: MessageKind::Common {
+                from: Sender::User(User {
+                    id: 0,
+                    is_bot: false,
+                    first_name: "".to_string(),
+                    last_name: None,
+                    username: None,
+                    language_code: None,
+                }),
+                forward_kind: ForwardKind::Origin {
+                    reply_to_message: None,
+                },
+                edit_date: None,
+                media_kind: MediaKind::Text {
+                    text,
+                    entities: vec![],
+                },
+                reply_markup: None,
+            },
+        }
+    }
+}
diff --git a/src/dispatching/filters/message_text_caption.rs b/src/dispatching/filters/message_text_caption.rs
new file mode 100644
index 00000000..5ee0df1f
--- /dev/null
+++ b/src/dispatching/filters/message_text_caption.rs
@@ -0,0 +1,152 @@
+use crate::{dispatching::Filter, types::Message};
+
+/// Filter which compare message text or caption of media with another text.
+/// Returns true if the message text or caption of media is equal to another
+/// text, otherwise false.
+///
+/// NOTE: filter compares text of message or if it is not exists, compares
+/// caption of the message!
+///
+/// If you want to compare only caption use
+/// [MessageCaptionFilter]
+///
+/// If you want to compare only text use
+/// [MessageTextFilter]
+///
+/// [MessageCaptionFilter]: telebofr::dispatching::filters::MessageCaptionFilter
+/// [MessageTextFilter]: telebofr::filter::filters::MessageTextFilter
+pub struct MessageTextCaptionFilter {
+    text: String,
+}
+
+impl Filter<Message> for MessageTextCaptionFilter {
+    fn test(&self, value: &Message) -> bool {
+        match value.text() {
+            Some(text) => self.text == text,
+            None => match value.caption() {
+                Some(caption) => self.text == caption,
+                None => false,
+            },
+        }
+    }
+}
+
+impl MessageTextCaptionFilter {
+    pub fn new<T>(text: T) -> Self
+    where
+        T: Into<String>,
+    {
+        Self { text: text.into() }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::types::{
+        Chat, ChatKind, ForwardKind, MediaKind, MessageKind, Sender, User,
+    };
+
+    #[test]
+    fn texts_are_equal() {
+        let filter = MessageTextCaptionFilter::new("text");
+        let message = create_message_with_text("text".to_string());
+        assert!(filter.test(&message));
+    }
+
+    #[test]
+    fn texts_are_not_equal() {
+        let filter = MessageTextCaptionFilter::new("text");
+        let message = create_message_with_text("not equal text".to_string());
+        assert_eq!(filter.test(&message), false);
+    }
+
+    fn create_message_with_text(text: String) -> Message {
+        Message {
+            id: 0,
+            date: 0,
+            chat: Chat {
+                id: 0,
+                kind: ChatKind::Private {
+                    type_: (),
+                    username: None,
+                    first_name: None,
+                    last_name: None,
+                },
+                photo: None,
+            },
+            kind: MessageKind::Common {
+                from: Sender::User(User {
+                    id: 0,
+                    is_bot: false,
+                    first_name: "".to_string(),
+                    last_name: None,
+                    username: None,
+                    language_code: None,
+                }),
+                forward_kind: ForwardKind::Origin {
+                    reply_to_message: None,
+                },
+                edit_date: None,
+                media_kind: MediaKind::Text {
+                    text,
+                    entities: vec![],
+                },
+                reply_markup: None,
+            },
+        }
+    }
+
+    #[test]
+    fn captions_are_equal() {
+        let filter = MessageTextCaptionFilter::new("caption".to_string());
+        let message = create_message_with_caption("caption".to_string());
+        assert!(filter.test(&message));
+    }
+
+    #[test]
+    fn captions_are_not_equal() {
+        let filter = MessageTextCaptionFilter::new("caption".to_string());
+        let message =
+            create_message_with_caption("not equal caption".to_string());
+        assert_eq!(filter.test(&message), false);
+    }
+
+    fn create_message_with_caption(caption: String) -> Message {
+        Message {
+            id: 0,
+            date: 0,
+            chat: Chat {
+                id: 0,
+                kind: ChatKind::Private {
+                    type_: (),
+                    username: None,
+                    first_name: None,
+                    last_name: None,
+                },
+                photo: None,
+            },
+            kind: MessageKind::Common {
+                from: Sender::User(User {
+                    id: 0,
+                    is_bot: false,
+                    first_name: "".to_string(),
+                    last_name: None,
+                    username: None,
+                    language_code: None,
+                }),
+                forward_kind: ForwardKind::Origin {
+                    reply_to_message: None,
+                },
+                edit_date: None,
+                media_kind: MediaKind::Photo {
+                    photo: vec![],
+                    caption: Some(caption),
+                    caption_entities: vec![],
+                    media_group_id: None,
+                },
+                reply_markup: None,
+            },
+        }
+    }
+}
diff --git a/src/dispatching/filters/mod.rs b/src/dispatching/filters/mod.rs
new file mode 100644
index 00000000..b3f9237f
--- /dev/null
+++ b/src/dispatching/filters/mod.rs
@@ -0,0 +1,13 @@
+pub use main::*;
+
+pub use command::*;
+pub use message_caption::*;
+pub use message_text::*;
+pub use message_text_caption::*;
+
+mod main;
+
+mod command;
+mod message_caption;
+mod message_text;
+mod message_text_caption;
diff --git a/src/dispatcher/handler.rs b/src/dispatching/handler.rs
similarity index 72%
rename from src/dispatcher/handler.rs
rename to src/dispatching/handler.rs
index 7c52928b..9ce74580 100644
--- a/src/dispatcher/handler.rs
+++ b/src/dispatching/handler.rs
@@ -1,12 +1,15 @@
+use std::{future::Future, pin::Pin};
+
 use futures::FutureExt;
-use std::future::Future;
-use std::pin::Pin;
 
 pub type HandlerResult<E> = Result<(), E>;
 
 /// Asynchronous handler for event `T` (like `&self, I -> Future` fn)
 pub trait Handler<'a, T, E> {
-    fn handle(&self, value: T) -> Pin<Box<dyn Future<Output = HandlerResult<E>> + 'a>>;
+    fn handle(
+        &self,
+        value: T,
+    ) -> Pin<Box<dyn Future<Output = HandlerResult<E>> + 'a>>;
 }
 
 pub trait IntoHandlerResult<E> {
@@ -32,7 +35,10 @@ where
     R: IntoHandlerResult<E> + 'a,
     E: 'a,
 {
-    fn handle(&self, value: T) -> Pin<Box<dyn Future<Output = HandlerResult<E>> + 'a>> {
+    fn handle(
+        &self,
+        value: T,
+    ) -> Pin<Box<dyn Future<Output = HandlerResult<E>> + 'a>> {
         Box::pin(self(value).map(IntoHandlerResult::into_hr))
     }
 }
diff --git a/src/dispatching/mod.rs b/src/dispatching/mod.rs
new file mode 100644
index 00000000..c239778f
--- /dev/null
+++ b/src/dispatching/mod.rs
@@ -0,0 +1,15 @@
+//! Update dispatching.
+
+use async_trait::async_trait;
+pub use filters::Filter;
+pub use handler::Handler;
+
+pub mod dispatchers;
+pub mod filters;
+pub mod handler;
+pub mod updater;
+
+#[async_trait(? Send)]
+pub trait Dispatcher<'a, U> {
+    async fn dispatch(&'a mut self, updater: U);
+}
diff --git a/src/dispatcher/updater.rs b/src/dispatching/updater.rs
similarity index 75%
rename from src/dispatcher/updater.rs
rename to src/dispatching/updater.rs
index 8dd14da1..47d131ec 100644
--- a/src/dispatcher/updater.rs
+++ b/src/dispatching/updater.rs
@@ -3,19 +3,17 @@ use std::{
     task::{Context, Poll},
 };
 
-use pin_project::pin_project;
-use futures::{Stream, StreamExt, stream};
+use futures::{stream, Stream, StreamExt};
 
-use crate::{
-    bot::Bot,
-    types::Update,
-    RequestError,
-};
+use pin_project::pin_project;
+
+use crate::{bot::Bot, types::Update, RequestError};
 
 // Currently just a placeholder, but I'll  add here some methods
 /// Updater is stream of updates.
 ///
-/// Telegram supports 2 ways of [getting updates]: [long polling](Long Polling) and webhook
+/// Telegram supports 2 ways of [getting updates]: [long polling](Long Polling)
+/// and webhook
 ///
 /// ## Long Polling
 ///
@@ -99,12 +97,16 @@ use crate::{
 /// [GetUpdates]: crate::requests::GetUpdates
 /// [getting updates]: https://core.telegram.org/bots/api#getting-updates
 /// [wiki]: https://en.wikipedia.org/wiki/Push_technology#Long_polling
-pub trait Updater<E>: Stream<Item=Result<Update, E>> {}
+pub trait Updater:
+    Stream<Item = Result<Update, <Self as Updater>::Error>>
+{
+    type Error;
+}
 
 #[pin_project]
 pub struct StreamUpdater<S> {
     #[pin]
-    stream: S
+    stream: S,
 }
 
 impl<S> StreamUpdater<S> {
@@ -113,35 +115,49 @@ impl<S> StreamUpdater<S> {
     }
 }
 
-impl<S, E> Stream for StreamUpdater<S> where S: Stream<Item=Result<Update, E>> {
+impl<S, E> Stream for StreamUpdater<S>
+where
+    S: Stream<Item = Result<Update, E>>,
+{
     type Item = Result<Update, E>;
 
-    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+    fn poll_next(
+        self: Pin<&mut Self>,
+        cx: &mut Context<'_>,
+    ) -> Poll<Option<Self::Item>> {
         self.project().stream.poll_next(cx)
     }
 }
 
-impl<S, E> Updater<E> for StreamUpdater<S> where S: Stream<Item=Result<Update, E>> {}
+impl<S, E> Updater for StreamUpdater<S>
+where
+    S: Stream<Item = Result<Update, E>>,
+{
+    type Error = E;
+}
 
-pub fn polling<'a>(bot: &'a Bot) -> impl Updater<RequestError> + 'a {
-    let stream = stream::unfold((bot, 0), |(bot, mut offset)| async move {
-        // this match converts Result<Vec<_>, _> -> Vec<Result<_, _>>
-        let updates = match bot.get_updates().offset(offset).send().await {
-            Ok(updates) => {
-                if let Some(upd) = updates.last() {
-                    offset = upd.id + 1;
+pub fn polling<'a>(bot: &'a Bot) -> impl Updater<Error = RequestError> + 'a {
+    let stream = stream::unfold((bot, 0), |(bot, mut offset)| {
+        async move {
+            // this match converts Result<Vec<_>, _> -> Vec<Result<_, _>>
+            let updates = match bot.get_updates().offset(offset).send().await {
+                Ok(updates) => {
+                    if let Some(upd) = updates.last() {
+                        offset = upd.id + 1;
+                    }
+                    updates.into_iter().map(Ok).collect::<Vec<_>>()
                 }
-                updates.into_iter().map(|u| Ok(u)).collect::<Vec<_>>()
-            },
-            Err(err) => vec![Err(err)]
-        };
-        Some((stream::iter(updates), (bot, offset)))
+                Err(err) => vec![Err(err)],
+            };
+            Some((stream::iter(updates), (bot, offset)))
+        }
     })
-        .flatten();
+    .flatten();
 
     StreamUpdater { stream }
 }
 
 // TODO implement webhook (this actually require webserver and probably we
 //   should add cargo feature that adds webhook)
-//pub fn webhook<'a>(bot: &'a Bot, cfg: WebhookConfig) -> Updater<impl Stream<Item=Result<Update, ???>> + 'a> {}
+//pub fn webhook<'a>(bot: &'a  cfg: WebhookConfig) -> Updater<impl
+// Stream<Item=Result<Update, ???>> + 'a> {}
diff --git a/src/lib.rs b/src/lib.rs
index 8d244ff6..838a211a 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,12 +5,13 @@ extern crate serde;
 #[macro_use]
 extern crate thiserror;
 
+pub use bot::Bot;
 pub use errors::{DownloadError, RequestError};
 
 mod errors;
 mod network;
 
-pub mod bot;
-pub mod dispatcher;
+mod bot;
+pub mod dispatching;
 pub mod requests;
 pub mod types;
diff --git a/src/network/request.rs b/src/network/request.rs
index 0222fad2..40bb8b2d 100644
--- a/src/network/request.rs
+++ b/src/network/request.rs
@@ -11,8 +11,8 @@ pub async fn request_multipart<T>(
     method_name: &str,
     params: Form,
 ) -> ResponseResult<T>
-    where
-        T: DeserializeOwned,
+where
+    T: DeserializeOwned,
 {
     process_response(
         client
@@ -30,8 +30,8 @@ pub async fn request_simple<T>(
     token: &str,
     method_name: &str,
 ) -> ResponseResult<T>
-    where
-        T: DeserializeOwned,
+where
+    T: DeserializeOwned,
 {
     process_response(
         client
diff --git a/src/network/telegram_response.rs b/src/network/telegram_response.rs
index 05e7acb7..82185c0c 100644
--- a/src/network/telegram_response.rs
+++ b/src/network/telegram_response.rs
@@ -1,7 +1,9 @@
 use reqwest::StatusCode;
 
 use crate::{
-    requests::ResponseResult, types::ResponseParameters, RequestError,
+    requests::ResponseResult,
+    types::{False, ResponseParameters, True},
+    RequestError,
 };
 
 #[derive(Deserialize)]
@@ -10,14 +12,14 @@ pub enum TelegramResponse<R> {
     Ok {
         /// A dummy field. Used only for deserialization.
         #[allow(dead_code)]
-        ok: bool, // TODO: True type
+        ok: True,
 
         result: R,
     },
     Err {
         /// A dummy field. Used only for deserialization.
         #[allow(dead_code)]
-        ok: bool, // TODO: False type
+        ok: False,
 
         description: String,
         error_code: u16,
diff --git a/src/requests/answer_callback_query.rs b/src/requests/answer_callback_query.rs
new file mode 100644
index 00000000..6bc42024
--- /dev/null
+++ b/src/requests/answer_callback_query.rs
@@ -0,0 +1,125 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::True,
+};
+
+/// Use this method to send answers to callback queries sent from inline
+/// keyboards. The answer will be displayed to the user as a notification at the
+/// top of the chat screen or as an alert. On success, True is returned.
+///
+/// Alternatively, the user can be redirected to the specified Game URL. For
+/// this option to work, you must first create a game for your bot via
+/// @Botfather and accept the terms. Otherwise, you may use links like
+/// t.me/your_bot?start=XXXX that open your bot with a parameter.
+#[derive(Debug, Clone, Serialize)]
+pub struct AnswerCallbackQuery<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    /// Unique identifier for the query to be answered.
+    callback_query_id: String,
+
+    /// Text of the notification. If not specified, nothing will be shown to
+    /// the user, 0-200 characters
+    #[serde(skip_serializing_if = "Option::is_none")]
+    text: Option<String>,
+
+    /// If true, an alert will be shown by the client instead of a notification
+    /// at the top of the chat screen. Defaults to false.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    show_alert: Option<bool>,
+
+    /// URL that will be opened by the user's client. If you have created a
+    /// Game and accepted the conditions via @Botfather, specify the URL that
+    /// opens your game – note that this will only work if the query comes from
+    /// a callback_game button.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    url: Option<String>,
+
+    /// The maximum amount of time in seconds that the result of the callback
+    /// query may be cached client-side. Telegram apps will support caching
+    /// starting in version 3.14. Defaults to 0.
+    #[serde(skip_serializing_if = "Option::is_none")]
+    cache_time: Option<i32>,
+}
+
+#[async_trait]
+impl Request for AnswerCallbackQuery<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl AnswerCallbackQuery<'_> {
+    pub async fn send(self) -> ResponseResult<True> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "answerCallbackQuery",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> AnswerCallbackQuery<'a> {
+    pub(crate) fn new<S>(bot: &'a Bot, callback_query_id: S) -> Self
+    where
+        S: Into<String>,
+    {
+        Self {
+            bot,
+            callback_query_id: callback_query_id.into(),
+            text: None,
+            show_alert: None,
+            url: None,
+            cache_time: None,
+        }
+    }
+
+    pub fn callback_query_id<S>(mut self, value: S) -> Self
+    where
+        S: Into<String>,
+    {
+        self.callback_query_id = value.into();
+        self
+    }
+
+    pub fn text<S>(mut self, value: S) -> Self
+    where
+        S: Into<String>,
+    {
+        self.text = Some(value.into());
+        self
+    }
+
+    pub fn show_alert<B>(mut self, value: B) -> Self
+    where
+        B: Into<bool>,
+    {
+        self.show_alert = Some(value.into());
+        self
+    }
+
+    pub fn url<S>(mut self, value: S) -> Self
+    where
+        S: Into<String>,
+    {
+        self.url = Some(value.into());
+        self
+    }
+
+    pub fn cache_time<I>(mut self, value: I) -> Self
+    where
+        I: Into<i32>,
+    {
+        self.cache_time = Some(value.into());
+        self
+    }
+}
diff --git a/src/requests/answer_pre_checkout_query.rs b/src/requests/answer_pre_checkout_query.rs
index b7f5bfe1..e4842ef9 100644
--- a/src/requests/answer_pre_checkout_query.rs
+++ b/src/requests/answer_pre_checkout_query.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::True,
 };
 
@@ -16,7 +17,7 @@ use crate::{
 /// [`Update`]: crate::types::Update
 pub struct AnswerPreCheckoutQuery<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     /// Unique identifier for the query to be answered
     pub pre_checkout_query_id: String,
@@ -48,8 +49,8 @@ impl Request for AnswerPreCheckoutQuery<'_> {
 impl AnswerPreCheckoutQuery<'_> {
     pub async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "answerPreCheckoutQuery",
             &self,
         )
@@ -59,7 +60,7 @@ impl AnswerPreCheckoutQuery<'_> {
 
 impl<'a> AnswerPreCheckoutQuery<'a> {
     pub(crate) fn new<S, B>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         pre_checkout_query_id: S,
         ok: B,
     ) -> Self
@@ -68,7 +69,7 @@ impl<'a> AnswerPreCheckoutQuery<'a> {
         B: Into<bool>,
     {
         Self {
-            ctx,
+            bot,
             pre_checkout_query_id: pre_checkout_query_id.into(),
             ok: ok.into(),
             error_message: None,
diff --git a/src/requests/answer_shipping_query.rs b/src/requests/answer_shipping_query.rs
index b7a25069..90b59fa9 100644
--- a/src/requests/answer_shipping_query.rs
+++ b/src/requests/answer_shipping_query.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ShippingOption, True},
 };
 
@@ -15,7 +16,7 @@ use crate::{
 /// [`Update`]: crate::types::Update
 pub struct AnswerShippingQuery<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     /// Unique identifier for the query to be answered
     pub shipping_query_id: String,
@@ -49,8 +50,8 @@ impl Request for AnswerShippingQuery<'_> {
 impl AnswerShippingQuery<'_> {
     pub async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "answerShippingQuery",
             &self,
         )
@@ -59,17 +60,13 @@ impl AnswerShippingQuery<'_> {
 }
 
 impl<'a> AnswerShippingQuery<'a> {
-    pub(crate) fn new<S, B>(
-        ctx: RequestContext<'a>,
-        shipping_query_id: S,
-        ok: B,
-    ) -> Self
+    pub(crate) fn new<S, B>(bot: &'a Bot, shipping_query_id: S, ok: B) -> Self
     where
         S: Into<String>,
         B: Into<bool>,
     {
         Self {
-            ctx,
+            bot,
             shipping_query_id: shipping_query_id.into(),
             ok: ok.into(),
             shipping_options: None,
diff --git a/src/requests/delete_chat_photo.rs b/src/requests/delete_chat_photo.rs
new file mode 100644
index 00000000..f674d4f9
--- /dev/null
+++ b/src/requests/delete_chat_photo.rs
@@ -0,0 +1,73 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, True},
+};
+
+#[derive(Debug, Clone, Serialize)]
+pub struct DeleteChatPhoto<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    chat_id: ChatId,
+}
+
+#[async_trait]
+impl Request for DeleteChatPhoto<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl DeleteChatPhoto<'_> {
+    async fn send(self) -> ResponseResult<True> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "deleteChatPhoto",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> DeleteChatPhoto<'a> {
+    pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let method = DeleteChatPhoto::new(&bot, chat_id);
+
+        let expected = r#"{"chat_id":123}"#;
+        let actual = serde_json::to_string::<DeleteChatPhoto>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
diff --git a/src/requests/delete_chat_sticker_set.rs b/src/requests/delete_chat_sticker_set.rs
new file mode 100644
index 00000000..63a5260f
--- /dev/null
+++ b/src/requests/delete_chat_sticker_set.rs
@@ -0,0 +1,64 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, True},
+};
+
+/// Use this method to delete a group sticker set from a supergroup. The bot
+/// must be an administrator in the chat for this to work and must have the
+/// appropriate admin rights. Use the field can_set_sticker_set optionally
+/// returned in getChat requests to check if the bot can use this method.
+/// Returns True on success.
+#[derive(Debug, Clone, Serialize)]
+pub struct DeleteChatStickerSet<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    /// Unique identifier for the target chat or username of the target
+    /// supergroup (in the format @supergroupusername)
+    chat_id: ChatId,
+}
+
+#[async_trait]
+impl Request for DeleteChatStickerSet<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl DeleteChatStickerSet<'_> {
+    async fn send(&self) -> ResponseResult<True> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "deleteChatStickerSet",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> DeleteChatStickerSet<'a> {
+    pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, value: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = value.into();
+        self
+    }
+}
diff --git a/src/requests/edit_message_live_location.rs b/src/requests/edit_message_live_location.rs
index c4c0fc4e..8ac0e77a 100644
--- a/src/requests/edit_message_live_location.rs
+++ b/src/requests/edit_message_live_location.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message, ReplyMarkup},
 };
 
@@ -17,7 +18,7 @@ use crate::{
 /// [`Message`]: crate::types::Message
 pub struct EditMessageLiveLocation<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     #[serde(skip_serializing_if = "Option::is_none")]
     /// Required if inline_message_id is not specified. Unique identifier for
@@ -53,8 +54,8 @@ impl Request for EditMessageLiveLocation<'_> {
 impl EditMessageLiveLocation<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "editMessageLiveLocation",
             &self,
         )
@@ -63,17 +64,13 @@ impl EditMessageLiveLocation<'_> {
 }
 
 impl<'a> EditMessageLiveLocation<'a> {
-    pub(crate) fn new<Lt, Lg>(
-        ctx: RequestContext<'a>,
-        latitude: Lt,
-        longitude: Lg,
-    ) -> Self
+    pub(crate) fn new<Lt, Lg>(bot: &'a Bot, latitude: Lt, longitude: Lg) -> Self
     where
         Lt: Into<f64>,
         Lg: Into<f64>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: None,
             message_id: None,
             inline_message_id: None,
diff --git a/src/requests/export_chat_invite_link.rs b/src/requests/export_chat_invite_link.rs
new file mode 100644
index 00000000..dfb809b0
--- /dev/null
+++ b/src/requests/export_chat_invite_link.rs
@@ -0,0 +1,74 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::ChatId,
+};
+
+#[derive(Debug, Clone, Serialize)]
+pub struct ExportCharInviteLink<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    chat_id: ChatId,
+}
+
+#[async_trait]
+impl Request for ExportCharInviteLink<'_> {
+    type Output = String;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl ExportCharInviteLink<'_> {
+    async fn send(self) -> ResponseResult<String> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "exportChatInviteLink",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> ExportCharInviteLink<'a> {
+    pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let method = ExportCharInviteLink::new(&bot, chat_id);
+
+        let expected = r#"{"chat_id":123}"#;
+        let actual =
+            serde_json::to_string::<ExportCharInviteLink>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
diff --git a/src/requests/form_builder.rs b/src/requests/form_builder.rs
index 0d292683..bc355eab 100644
--- a/src/requests/form_builder.rs
+++ b/src/requests/form_builder.rs
@@ -79,7 +79,10 @@ macro_rules! impl_for_struct {
 
 impl_for_struct!(bool, i32, i64);
 
-impl<T> IntoFormValue for Option<T> where T: IntoFormValue {
+impl<T> IntoFormValue for Option<T>
+where
+    T: IntoFormValue,
+{
     fn into_form_value(self) -> Option<FormValue> {
         self.and_then(IntoFormValue::into_form_value)
     }
@@ -87,8 +90,8 @@ impl<T> IntoFormValue for Option<T> where T: IntoFormValue {
 
 impl IntoFormValue for &[InputMedia] {
     fn into_form_value(self) -> Option<FormValue> {
-        let json = serde_json::to_string(self)
-            .expect("serde_json::to_string failed");
+        let json =
+            serde_json::to_string(self).expect("serde_json::to_string failed");
         Some(FormValue::Str(json))
     }
 }
@@ -113,7 +116,7 @@ impl IntoFormValue for ChatId {
     fn into_form_value(self) -> Option<FormValue> {
         let string = match self {
             ChatId::Id(id) => id.to_string(),
-            ChatId::ChannelUsername(username) => username.clone(),
+            ChatId::ChannelUsername(username) => username,
         };
         Some(FormValue::Str(string))
     }
@@ -121,7 +124,7 @@ impl IntoFormValue for ChatId {
 
 impl IntoFormValue for String {
     fn into_form_value(self) -> Option<FormValue> {
-        Some(FormValue::Str(self.to_owned()))
+        Some(FormValue::Str(self))
     }
 }
 
diff --git a/src/requests/forward_message.rs b/src/requests/forward_message.rs
index 9c16ae67..b99166b0 100644
--- a/src/requests/forward_message.rs
+++ b/src/requests/forward_message.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message},
 };
 
@@ -11,7 +12,7 @@ use crate::{
 /// [`Message`] is returned.
 pub struct ForwardMessage<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     /// Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
@@ -40,8 +41,8 @@ impl Request for ForwardMessage<'_> {
 impl ForwardMessage<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            self.ctx.client,
-            self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "forwardMessage",
             &self,
         )
@@ -51,7 +52,7 @@ impl ForwardMessage<'_> {
 
 impl<'a> ForwardMessage<'a> {
     pub(crate) fn new<C, Fc, M>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         chat_id: C,
         from_chat_id: Fc,
         message_id: M,
@@ -62,7 +63,7 @@ impl<'a> ForwardMessage<'a> {
         M: Into<i32>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             from_chat_id: from_chat_id.into(),
             message_id: message_id.into(),
diff --git a/src/requests/get_chat.rs b/src/requests/get_chat.rs
index 7135f226..6a8bc711 100644
--- a/src/requests/get_chat.rs
+++ b/src/requests/get_chat.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{Chat, ChatId},
 };
 
@@ -13,7 +14,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct GetChat<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or username
     /// of the target supergroup or channel (in the format @channelusername)
     chat_id: ChatId,
@@ -31,8 +32,8 @@ impl Request for GetChat<'_> {
 impl GetChat<'_> {
     pub async fn send(self) -> ResponseResult<Chat> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "getChat",
             &self,
         )
@@ -41,11 +42,21 @@ impl GetChat<'_> {
 }
 
 impl<'a> GetChat<'a> {
-    pub fn chat_id<C>(mut self, value: C) -> Self
+    pub(crate) fn new<F>(bot: &'a Bot, chat_id: F) -> Self
+    where
+        F: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
     where
         C: Into<ChatId>,
     {
-        self.chat_id = value.into();
+        self.chat_id = chat_id.into();
         self
     }
 }
diff --git a/src/requests/get_chat_administrators.rs b/src/requests/get_chat_administrators.rs
new file mode 100644
index 00000000..ba35a99c
--- /dev/null
+++ b/src/requests/get_chat_administrators.rs
@@ -0,0 +1,64 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, ChatMember},
+};
+
+/// Use this method to get a list of administrators in a chat. On success,
+/// returns an Array of ChatMember objects that contains information about all
+/// chat administrators except other bots. If the chat is a group or a
+/// supergroup and no administrators were appointed, only the creator will be
+/// returned
+#[derive(Debug, Clone, Serialize)]
+pub struct GetChatAdministrators<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    /// Unique identifier for the target chat or username of the target
+    /// supergroup or channel (in the format @channelusername)
+    chat_id: ChatId,
+}
+
+#[async_trait]
+impl Request for GetChatAdministrators<'_> {
+    type Output = Vec<ChatMember>;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl GetChatAdministrators<'_> {
+    async fn send(&self) -> ResponseResult<Vec<ChatMember>> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "getChatAdministrators",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> GetChatAdministrators<'a> {
+    pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, value: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = value.into();
+        self
+    }
+}
diff --git a/src/requests/get_chat_member.rs b/src/requests/get_chat_member.rs
new file mode 100644
index 00000000..3a03fd12
--- /dev/null
+++ b/src/requests/get_chat_member.rs
@@ -0,0 +1,74 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, ChatMember},
+};
+
+/// Use this method to get information about a member of a chat. Returns a
+/// ChatMember object on success.
+#[derive(Debug, Clone, Serialize)]
+pub struct GetChatMember<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    /// Unique identifier for the target chat or username of the target
+    /// supergroup or channel (in the format @channelusername)
+    chat_id: ChatId,
+
+    /// Unique identifier of the target user
+    user_id: i32,
+}
+
+#[async_trait]
+impl Request for GetChatMember<'_> {
+    type Output = ChatMember;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl GetChatMember<'_> {
+    async fn send(&self) -> ResponseResult<ChatMember> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "getChatMember",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> GetChatMember<'a> {
+    pub(crate) fn new<C, I>(bot: &'a Bot, chat_id: C, user_id: I) -> Self
+    where
+        C: Into<ChatId>,
+        I: Into<i32>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+            user_id: user_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, value: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = value.into();
+        self
+    }
+
+    pub fn user_id<I>(mut self, value: I) -> Self
+    where
+        I: Into<i32>,
+    {
+        self.user_id = value.into();
+        self
+    }
+}
diff --git a/src/requests/get_chat_members_count.rs b/src/requests/get_chat_members_count.rs
new file mode 100644
index 00000000..ae224c59
--- /dev/null
+++ b/src/requests/get_chat_members_count.rs
@@ -0,0 +1,61 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{Chat, ChatId},
+};
+
+/// Use this method to get the number of members in a chat. Returns Int on
+/// success.
+#[derive(Debug, Clone, Serialize)]
+pub struct GetChatMembersCount<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    /// Unique identifier for the target chat or username
+    /// of the target supergroup or channel (in the format @channelusername)
+    chat_id: ChatId,
+}
+
+#[async_trait]
+impl Request for GetChatMembersCount<'_> {
+    type Output = Chat;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl GetChatMembersCount<'_> {
+    pub async fn send(self) -> ResponseResult<Chat> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "getChatMembersCount",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> GetChatMembersCount<'a> {
+    pub fn new<C>(bot: &'a Bot, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, value: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = value.into();
+        self
+    }
+}
diff --git a/src/requests/get_file.rs b/src/requests/get_file.rs
index 59785b17..43cb809d 100644
--- a/src/requests/get_file.rs
+++ b/src/requests/get_file.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::File,
 };
 
@@ -16,7 +17,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct GetFile<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// File identifier to get info about
     pub file_id: String,
 }
@@ -33,8 +34,8 @@ impl Request for GetFile<'_> {
 impl GetFile<'_> {
     pub async fn send(self) -> ResponseResult<File> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "getFile",
             &self,
         )
@@ -43,12 +44,12 @@ impl GetFile<'_> {
 }
 
 impl<'a> GetFile<'a> {
-    pub(crate) fn new<F>(ctx: RequestContext<'a>, value: F) -> Self
+    pub(crate) fn new<F>(bot: &'a Bot, value: F) -> Self
     where
         F: Into<String>,
     {
         Self {
-            ctx,
+            bot,
             file_id: value.into(),
         }
     }
diff --git a/src/requests/get_me.rs b/src/requests/get_me.rs
index 20cfa3ef..6efe9543 100644
--- a/src/requests/get_me.rs
+++ b/src/requests/get_me.rs
@@ -1,16 +1,17 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::User,
 };
 
 #[derive(Debug, Clone)]
-/// A simple method for testing your bot's auth token. Requires no parameters.
+/// A filter method for testing your bot's auth token. Requires no parameters.
 /// Returns basic information about the bot in form of a [`User`] object.
 pub struct GetMe<'a> {
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 }
 
 #[async_trait]
@@ -24,12 +25,13 @@ impl Request for GetMe<'_> {
 
 impl GetMe<'_> {
     pub async fn send(self) -> ResponseResult<User> {
-        network::request_simple(self.ctx.client, self.ctx.token, "getMe").await
+        network::request_simple(self.bot.client(), self.bot.token(), "getMe")
+            .await
     }
 }
 
 impl<'a> GetMe<'a> {
-    pub(crate) fn new(ctx: RequestContext<'a>) -> Self {
-        GetMe { ctx }
+    pub(crate) fn new(bot: &'a Bot) -> Self {
+        GetMe { bot }
     }
 }
diff --git a/src/requests/get_updates.rs b/src/requests/get_updates.rs
index 176a0e91..8e25a784 100644
--- a/src/requests/get_updates.rs
+++ b/src/requests/get_updates.rs
@@ -1,15 +1,16 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::Update,
 };
 
 #[derive(Debug, Clone, Serialize)]
 pub struct GetUpdates<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     pub offset: Option<i32>,
     pub limit: Option<u8>,
@@ -41,8 +42,8 @@ impl Request for GetUpdates<'_> {
 impl GetUpdates<'_> {
     pub async fn send(self) -> ResponseResult<Vec<Update>> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "getUpdates",
             &self,
         )
@@ -51,9 +52,9 @@ impl GetUpdates<'_> {
 }
 
 impl<'a> GetUpdates<'a> {
-    pub(crate) fn new(ctx: RequestContext<'a>) -> Self {
+    pub(crate) fn new(bot: &'a Bot) -> Self {
         Self {
-            ctx,
+            bot,
             offset: None,
             limit: None,
             timeout: None,
diff --git a/src/requests/get_user_profile_photos.rs b/src/requests/get_user_profile_photos.rs
index 6044441d..88ccaf5a 100644
--- a/src/requests/get_user_profile_photos.rs
+++ b/src/requests/get_user_profile_photos.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::UserProfilePhotos,
 };
 
@@ -11,7 +12,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct GetUserProfilePhotos<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier of the target user
     pub user_id: i32,
     /// Sequential number of the first photo to be returned. By default, all
@@ -36,8 +37,8 @@ impl Request for GetUserProfilePhotos<'_> {
 impl GetUserProfilePhotos<'_> {
     async fn send(self) -> ResponseResult<UserProfilePhotos> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "getUserProfilePhotos",
             &self,
         )
@@ -46,12 +47,12 @@ impl GetUserProfilePhotos<'_> {
 }
 
 impl<'a> GetUserProfilePhotos<'a> {
-    pub fn new<U>(ctx: RequestContext<'a>, user_id: U) -> Self
+    pub fn new<U>(bot: &'a Bot, user_id: U) -> Self
     where
         U: Into<i32>,
     {
         Self {
-            ctx,
+            bot,
             user_id: user_id.into(),
             offset: None,
             limit: None,
diff --git a/src/requests/kick_chat_member.rs b/src/requests/kick_chat_member.rs
index 9dec2cd6..cdbef073 100644
--- a/src/requests/kick_chat_member.rs
+++ b/src/requests/kick_chat_member.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, True},
 };
 
@@ -14,7 +15,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct KickChatMember<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target group or username of the target
     /// supergroup or channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -39,8 +40,8 @@ impl Request for KickChatMember<'_> {
 impl KickChatMember<'_> {
     async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            self.ctx.client,
-            self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "kickChatMember",
             &self,
         )
@@ -49,17 +50,13 @@ impl KickChatMember<'_> {
 }
 
 impl<'a> KickChatMember<'a> {
-    pub(crate) fn new<C, U>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        user_id: U,
-    ) -> Self
+    pub(crate) fn new<C, U>(bot: &'a Bot, chat_id: C, user_id: U) -> Self
     where
         C: Into<ChatId>,
         U: Into<i32>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             user_id: user_id.into(),
             until_date: None,
diff --git a/src/requests/leave_chat.rs b/src/requests/leave_chat.rs
new file mode 100644
index 00000000..1f52a1f6
--- /dev/null
+++ b/src/requests/leave_chat.rs
@@ -0,0 +1,59 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::ChatId,
+};
+
+/// Use this method for your bot to leave a group, supergroup or channel.
+/// Returns True on success.
+#[derive(Debug, Clone, Serialize)]
+pub struct LeaveChat<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+    /// Unique identifier for the target chat or username
+    /// of the target supergroup or channel (in the format @channelusername)
+    chat_id: ChatId,
+}
+
+#[async_trait]
+impl Request for LeaveChat<'_> {
+    type Output = bool;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl LeaveChat<'_> {
+    pub async fn send(self) -> ResponseResult<bool> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "leaveChat",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> LeaveChat<'a> {
+    pub(crate) fn new<F>(bot: &'a Bot, chat_id: F) -> Self
+    where
+        F: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+        }
+    }
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+}
diff --git a/src/requests/mod.rs b/src/requests/mod.rs
index 50f7ffaa..e9bbc265 100644
--- a/src/requests/mod.rs
+++ b/src/requests/mod.rs
@@ -1,45 +1,70 @@
-//! Raw API functions.
+//! API requests.
 
-use reqwest::Client;
-use serde::de::DeserializeOwned;
-
-use async_trait::async_trait;
-
-use crate::RequestError;
-
-pub use self::{
-    answer_pre_checkout_query::AnswerPreCheckoutQuery,
-    answer_shipping_query::AnswerShippingQuery,
-    edit_message_live_location::EditMessageLiveLocation,
-    forward_message::ForwardMessage, get_chat::GetChat, get_file::GetFile,
-    get_me::GetMe, get_updates::GetUpdates,
-    get_user_profile_photos::GetUserProfilePhotos,
-    kick_chat_member::KickChatMember, pin_chat_message::PinChatMessage,
-    promote_chat_member::PromoteChatMember,
-    restrict_chat_member::RestrictChatMember, send_animation::SendAnimation,
-    send_audio::SendAudio, send_chat_action::SendChatAction,
-    send_contact::SendContact, send_document::SendDocument,
-    send_location::SendLocation, send_media_group::SendMediaGroup,
-    send_message::SendMessage, send_photo::SendPhoto, send_poll::SendPoll,
-    send_venue::SendVenue, send_video::SendVideo,
-    send_video_note::SendVideoNote, send_voice::SendVoice,
-    stop_message_live_location::StopMessageLiveLocation,
-    unban_chat_member::UnbanChatMember, unpin_chat_message::UnpinChatMessage,
-};
+pub use answer_callback_query::*;
+pub use answer_pre_checkout_query::*;
+pub use answer_shipping_query::*;
+pub use delete_chat_photo::*;
+pub use delete_chat_sticker_set::*;
+pub use edit_message_live_location::*;
+pub use export_chat_invite_link::*;
+pub use forward_message::*;
+pub use get_chat::*;
+pub use get_chat_administrators::*;
+pub use get_chat_member::*;
+pub use get_chat_members_count::*;
+pub use get_file::*;
+pub use get_me::*;
+pub use get_updates::*;
+pub use get_user_profile_photos::*;
+pub use kick_chat_member::*;
+pub use leave_chat::*;
+pub use pin_chat_message::*;
+pub use promote_chat_member::*;
+pub use restrict_chat_member::*;
+pub use send_animation::*;
+pub use send_audio::*;
+pub use send_chat_action::*;
+pub use send_contact::*;
+pub use send_document::*;
+pub use send_location::*;
+pub use send_media_group::*;
+pub use send_message::*;
+pub use send_photo::*;
+pub use send_poll::*;
+pub use send_venue::*;
+pub use send_video::*;
+pub use send_video_note::*;
+pub use send_voice::*;
+pub use set_chat_description::*;
+pub use set_chat_permissions::*;
+pub use set_chat_photo::*;
+pub use set_chat_sticker_set::*;
+pub use set_chat_title::*;
+pub use stop_message_live_location::*;
+pub use unban_chat_member::*;
+pub use unpin_chat_message::*;
 
 mod form_builder;
 mod utils;
 
+mod answer_callback_query;
 mod answer_pre_checkout_query;
 mod answer_shipping_query;
+mod delete_chat_photo;
+mod delete_chat_sticker_set;
 mod edit_message_live_location;
+mod export_chat_invite_link;
 mod forward_message;
 mod get_chat;
+mod get_chat_administrators;
+mod get_chat_member;
+mod get_chat_members_count;
 mod get_file;
 mod get_me;
 mod get_updates;
 mod get_user_profile_photos;
 mod kick_chat_member;
+mod leave_chat;
 mod pin_chat_message;
 mod promote_chat_member;
 mod restrict_chat_member;
@@ -57,12 +82,20 @@ mod send_venue;
 mod send_video;
 mod send_video_note;
 mod send_voice;
+mod set_chat_description;
+mod set_chat_permissions;
+mod set_chat_photo;
+mod set_chat_sticker_set;
+mod set_chat_title;
 mod stop_message_live_location;
 mod unban_chat_member;
 mod unpin_chat_message;
 
+use async_trait::async_trait;
+use serde::de::DeserializeOwned;
+
 /// A type that is returned from `Request::send_boxed`.
-pub type ResponseResult<T> = Result<T, RequestError>;
+pub type ResponseResult<T> = Result<T, crate::RequestError>;
 
 /// A request that can be sent to Telegram.
 #[async_trait]
@@ -73,12 +106,3 @@ pub trait Request {
     /// Send this request.
     async fn send_boxed(self) -> ResponseResult<Self::Output>;
 }
-
-/// A context used to send all the requests.
-#[derive(Debug, Clone)]
-pub struct RequestContext<'a> {
-    /// An HTTPS client.
-    pub client: &'a Client,
-    /// A token of your bot.
-    pub token: &'a str,
-}
diff --git a/src/requests/pin_chat_message.rs b/src/requests/pin_chat_message.rs
index 9033e4dd..c8567e36 100644
--- a/src/requests/pin_chat_message.rs
+++ b/src/requests/pin_chat_message.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, True},
 };
 
@@ -13,7 +14,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct PinChatMessage<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or username
     /// of the target supergroup or channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -22,17 +23,13 @@ pub struct PinChatMessage<'a> {
 }
 
 impl<'a> PinChatMessage<'a> {
-    pub(crate) fn new<C, M>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        message_id: M,
-    ) -> Self
+    pub(crate) fn new<C, M>(bot: &'a Bot, chat_id: C, message_id: M) -> Self
     where
         C: Into<ChatId>,
         M: Into<i32>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             message_id: message_id.into(),
             disable_notification: None,
@@ -59,8 +56,8 @@ impl Request for PinChatMessage<'_> {
 impl PinChatMessage<'_> {
     async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "pinChatMessage",
             &self,
         )
diff --git a/src/requests/promote_chat_member.rs b/src/requests/promote_chat_member.rs
index d6c47d9d..2c416233 100644
--- a/src/requests/promote_chat_member.rs
+++ b/src/requests/promote_chat_member.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, True},
 };
 
@@ -13,7 +14,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct PromoteChatMember<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
     pub chat_id: ChatId,
@@ -62,8 +63,8 @@ impl Request for PromoteChatMember<'_> {
 impl PromoteChatMember<'_> {
     pub async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "promoteChatMember",
             &self,
         )
@@ -72,17 +73,13 @@ impl PromoteChatMember<'_> {
 }
 
 impl<'a> PromoteChatMember<'a> {
-    pub(crate) fn new<C, U>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        user_id: U,
-    ) -> Self
+    pub(crate) fn new<C, U>(bot: &'a Bot, chat_id: C, user_id: U) -> Self
     where
         C: Into<ChatId>,
         U: Into<i32>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             user_id: user_id.into(),
             can_change_info: None,
diff --git a/src/requests/restrict_chat_member.rs b/src/requests/restrict_chat_member.rs
index 5243484e..f17b5ba6 100644
--- a/src/requests/restrict_chat_member.rs
+++ b/src/requests/restrict_chat_member.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, ChatPermissions, True},
 };
 
@@ -13,7 +14,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct RestrictChatMember<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target chat or username of the target
     /// supergroup (in the format @supergroupusername)
     pub chat_id: ChatId,
@@ -40,8 +41,8 @@ impl Request for RestrictChatMember<'_> {
 impl RestrictChatMember<'_> {
     async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "restrictChatMember",
             &self,
         )
@@ -51,7 +52,7 @@ impl RestrictChatMember<'_> {
 
 impl<'a> RestrictChatMember<'a> {
     pub(crate) fn new<C, U, P>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         chat_id: C,
         user_id: U,
         permissions: P,
@@ -62,7 +63,7 @@ impl<'a> RestrictChatMember<'a> {
         P: Into<ChatPermissions>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             user_id: user_id.into(),
             permissions: permissions.into(),
diff --git a/src/requests/send_animation.rs b/src/requests/send_animation.rs
index 96b08299..0bfa8a3e 100644
--- a/src/requests/send_animation.rs
+++ b/src/requests/send_animation.rs
@@ -1,10 +1,12 @@
 use async_trait::async_trait;
 
-use crate::network;
-use crate::requests::{Request, RequestContext, ResponseResult};
-use crate::types::{ChatId, Message, ParseMode, ReplyMarkup};
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
+};
 
-///TODO: add to bot api
 ///Use this method to send animation files (GIF or H.264/MPEG-4 AVC video
 /// without sound). On success, the sent Message is returned. Bots can currently
 /// send animation files of up to 50 MB in size, this limit may be changed in
@@ -12,7 +14,7 @@ use crate::types::{ChatId, Message, ParseMode, ReplyMarkup};
 #[derive(Debug, Clone, Serialize)]
 pub struct SendAnimation<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
     pub chat_id: ChatId,
@@ -20,8 +22,7 @@ pub struct SendAnimation<'a> {
     /// exists on the Telegram servers (recommended), pass an HTTP URL as a
     /// String for Telegram to get an animation from the Internet, or upload a
     /// new animation using multipart/form-data. More info on Sending Files »
-    pub animation: String,
-    //	InputFile or String
+    pub animation: InputFile,
     ///Duration of sent animation in seconds
     #[serde(skip_serializing_if = "Option::is_none")]
     pub duration: Option<u64>,
@@ -40,8 +41,7 @@ pub struct SendAnimation<'a> {
     /// if the thumbnail was uploaded using multipart/form-data under
     /// <file_attach_name> »
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub thumb: Option<String>,
-    //	InputFile or String 	Optional
+    pub thumb: Option<InputFile>,
     ///Animation caption (may also be used when resending animation by
     /// file_id), 0-1024 characters
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -76,8 +76,8 @@ impl Request for SendAnimation<'_> {
 impl SendAnimation<'_> {
     async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendAnimation",
             &self,
         )
@@ -86,17 +86,13 @@ impl SendAnimation<'_> {
 }
 
 impl<'a> SendAnimation<'a> {
-    pub(crate) fn new<C, S>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        animation: S,
-    ) -> Self
+    pub(crate) fn new<C, S>(bot: &'a Bot, chat_id: C, animation: S) -> Self
     where
         C: Into<ChatId>,
-        S: Into<String>,
+        S: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             animation: animation.into(),
             duration: None,
@@ -143,7 +139,7 @@ impl<'a> SendAnimation<'a> {
     }
     pub fn thumb<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.thumb = Some(value.into());
         self
diff --git a/src/requests/send_audio.rs b/src/requests/send_audio.rs
index 731f47ad..95d29b61 100644
--- a/src/requests/send_audio.rs
+++ b/src/requests/send_audio.rs
@@ -1,10 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{
-        form_builder::FormBuilder, Request, RequestContext, ResponseResult,
-    },
+    requests::{form_builder::FormBuilder, Request, ResponseResult},
     types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
 };
 
@@ -18,7 +17,7 @@ use crate::{
 /// [`Message`]: crate::types::Message
 /// [`SendVoice`]: crate::requests::SendVoice
 pub struct SendAudio<'a> {
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     /// Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
@@ -86,10 +85,9 @@ impl SendAudio<'_> {
             .add("audio", self.audio)
             .add("thumb", self.thumb);
 
-
         network::request_multipart(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendAudio",
             params.build(),
         )
@@ -98,17 +96,13 @@ impl SendAudio<'_> {
 }
 
 impl<'a> SendAudio<'a> {
-    pub(crate) fn new<C, A>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        audio: A,
-    ) -> Self
+    pub(crate) fn new<C, A>(bot: &'a Bot, chat_id: C, audio: A) -> Self
     where
         C: Into<ChatId>,
         A: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             audio: audio.into(),
             caption: None,
diff --git a/src/requests/send_chat_action.rs b/src/requests/send_chat_action.rs
index 54e898bb..af4db368 100644
--- a/src/requests/send_chat_action.rs
+++ b/src/requests/send_chat_action.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatAction, ChatId, True},
 };
 
@@ -13,7 +14,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct SendChatAction<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or
     /// username of the target channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -37,8 +38,8 @@ impl Request for SendChatAction<'_> {
 impl SendChatAction<'_> {
     pub async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendChatAction",
             &self,
         )
@@ -47,17 +48,13 @@ impl SendChatAction<'_> {
 }
 
 impl<'a> SendChatAction<'a> {
-    pub(crate) fn new<Cid, Ca>(
-        ctx: RequestContext<'a>,
-        chat_id: Cid,
-        action: Ca,
-    ) -> Self
+    pub(crate) fn new<Cid, Ca>(bot: &'a Bot, chat_id: Cid, action: Ca) -> Self
     where
         Cid: Into<ChatId>,
         Ca: Into<ChatAction>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             action: action.into(),
         }
diff --git a/src/requests/send_contact.rs b/src/requests/send_contact.rs
index 307fb321..56e64cf9 100644
--- a/src/requests/send_contact.rs
+++ b/src/requests/send_contact.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message, ReplyMarkup},
 };
 
@@ -11,7 +12,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct SendContact<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or
     /// username of the target channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -54,8 +55,8 @@ impl Request for SendContact<'_> {
 impl SendContact<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendContact",
             &self,
         )
@@ -65,7 +66,7 @@ impl SendContact<'_> {
 
 impl<'a> SendContact<'a> {
     pub(crate) fn new<C, P, F>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         chat_id: C,
         phone_number: P,
         first_name: F,
@@ -76,7 +77,7 @@ impl<'a> SendContact<'a> {
         F: Into<String>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             phone_number: phone_number.into(),
             first_name: first_name.into(),
diff --git a/src/requests/send_document.rs b/src/requests/send_document.rs
index 298baa02..9224955c 100644
--- a/src/requests/send_document.rs
+++ b/src/requests/send_document.rs
@@ -1,20 +1,19 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
-    types::{ChatId, Message, ParseMode, ReplyMarkup},
+    requests::{Request, ResponseResult},
+    types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
 };
 
-// TODO: add method to bot/api
-
 ///Use this method to send general files. On success, the sent Message is
 /// returned. Bots can currently send files of any type of up to 50 MB in size,
 /// this limit may be changed in the future.
 #[derive(Debug, Clone, Serialize)]
 pub struct SendDocument<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or username of the target
     /// channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -22,8 +21,7 @@ pub struct SendDocument<'a> {
     /// the Telegram servers (recommended), pass an HTTP URL as a String for
     /// Telegram to get a file from the Internet, or upload a new one using
     /// multipart/form-data.»
-    pub document: String,
-    //InputFile or String
+    pub document: InputFile,
     /// Thumbnail of the file sent; can be ignored if thumbnail generation for
     /// the file is supported server-side. The thumbnail should be in JPEG
     /// format and less than 200 kB in size. A thumbnail‘s width and height
@@ -33,8 +31,7 @@ pub struct SendDocument<'a> {
     /// if the thumbnail was uploaded using multipart/form-data under
     /// <file_attach_name>. More info on Sending Files »
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub thumb: Option<String>,
-    //InputFile or String
+    pub thumb: Option<InputFile>,
     /// Document caption (may also be used when resending documents by
     /// file_id), 0-1024 characters
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -69,8 +66,8 @@ impl Request for SendDocument<'_> {
 impl SendDocument<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendDocument",
             &self,
         )
@@ -79,17 +76,13 @@ impl SendDocument<'_> {
 }
 
 impl<'a> SendDocument<'a> {
-    pub(crate) fn new<C, D>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        document: D,
-    ) -> Self
+    pub(crate) fn new<C, D>(bot: &'a Bot, chat_id: C, document: D) -> Self
     where
         C: Into<ChatId>,
-        D: Into<String>,
+        D: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             document: document.into(),
             thumb: None,
@@ -111,7 +104,7 @@ impl<'a> SendDocument<'a> {
 
     pub fn document<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.document = value.into();
         self
@@ -119,7 +112,7 @@ impl<'a> SendDocument<'a> {
 
     pub fn thumb<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.thumb = Some(value.into());
         self
diff --git a/src/requests/send_location.rs b/src/requests/send_location.rs
index a37162b2..bd76e9a2 100644
--- a/src/requests/send_location.rs
+++ b/src/requests/send_location.rs
@@ -3,8 +3,9 @@ use serde::Serialize;
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message, ReplyMarkup},
 };
 
@@ -13,7 +14,7 @@ use crate::{
 /// is returned.
 pub struct SendLocation<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     /// Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
@@ -50,8 +51,8 @@ impl Request for SendLocation<'_> {
 impl SendLocation<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendLocation",
             &self,
         )
@@ -61,7 +62,7 @@ impl SendLocation<'_> {
 
 impl<'a> SendLocation<'a> {
     pub(crate) fn new<Lt, Lg, C>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         chat_id: C,
         latitude: Lt,
         longitude: Lg,
@@ -72,7 +73,7 @@ impl<'a> SendLocation<'a> {
         C: Into<ChatId>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             latitude: latitude.into(),
             longitude: longitude.into(),
diff --git a/src/requests/send_media_group.rs b/src/requests/send_media_group.rs
index d189a926..ea503ed8 100644
--- a/src/requests/send_media_group.rs
+++ b/src/requests/send_media_group.rs
@@ -1,17 +1,16 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network::request_multipart,
-    requests::{
-        form_builder::FormBuilder, Request, RequestContext, ResponseResult,
-    },
-    types::{ChatId, InputMedia, Message, InputFile},
+    requests::{form_builder::FormBuilder, Request, ResponseResult},
+    types::{ChatId, InputFile, InputMedia, Message},
 };
 
 /// Use this method to send a group of photos or videos as an album.
 #[derive(Debug, Clone)]
 pub struct SendMediaGroup<'a> {
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     pub chat_id: ChatId,
     pub media: Vec<InputMedia>,
@@ -37,17 +36,20 @@ impl SendMediaGroup<'_> {
             .add("disable_notification", self.disable_notification)
             .add("reply_to_message_id", self.reply_to_message_id);
 
-        let form = self.media.into_iter().filter_map(|e| InputFile::from(e).into())
-                .fold(form, |acc, path: std::path::PathBuf|
-                    acc.add_file(
-                        &path.file_name().unwrap().to_string_lossy().into_owned(),
-                        path,
-                    )
-                );
+        let form = self
+            .media
+            .into_iter()
+            .filter_map(|e| InputFile::from(e).into())
+            .fold(form, |acc, path: std::path::PathBuf| {
+                acc.add_file(
+                    &path.file_name().unwrap().to_string_lossy().into_owned(),
+                    path,
+                )
+            });
 
         request_multipart(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendMediaGroup",
             form.build(),
         )
@@ -56,17 +58,13 @@ impl SendMediaGroup<'_> {
 }
 
 impl<'a> SendMediaGroup<'a> {
-    pub(crate) fn new<C, M>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        media: M,
-    ) -> Self
+    pub(crate) fn new<C, M>(bot: &'a Bot, chat_id: C, media: M) -> Self
     where
         C: Into<ChatId>,
         M: Into<Vec<InputMedia>>,
     {
         SendMediaGroup {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             media: media.into(),
             disable_notification: None,
diff --git a/src/requests/send_message.rs b/src/requests/send_message.rs
index adca7c4f..cd16ca21 100644
--- a/src/requests/send_message.rs
+++ b/src/requests/send_message.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message, ParseMode, ReplyMarkup},
 };
 
@@ -11,7 +12,7 @@ use crate::{
 /// returned.
 pub struct SendMessage<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     ///	Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
@@ -55,8 +56,8 @@ impl Request for SendMessage<'_> {
 impl SendMessage<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            self.ctx.client,
-            self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendMessage",
             &self,
         )
@@ -65,17 +66,13 @@ impl SendMessage<'_> {
 }
 
 impl<'a> SendMessage<'a> {
-    pub(crate) fn new<C, S>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        text: S,
-    ) -> Self
+    pub(crate) fn new<C, S>(bot: &'a Bot, chat_id: C, text: S) -> Self
     where
         C: Into<ChatId>,
         S: Into<String>,
     {
         SendMessage {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             text: text.into(),
             parse_mode: None,
diff --git a/src/requests/send_photo.rs b/src/requests/send_photo.rs
index 8092a55a..76c1b18b 100644
--- a/src/requests/send_photo.rs
+++ b/src/requests/send_photo.rs
@@ -1,10 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{
-        form_builder::FormBuilder, Request, RequestContext, ResponseResult,
-    },
+    requests::{form_builder::FormBuilder, Request, ResponseResult},
     types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
 };
 
@@ -12,7 +11,7 @@ use crate::{
 /// Use this method to send photos. On success, the sent [`Message`] is
 /// returned.
 pub struct SendPhoto<'a> {
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     /// Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
@@ -64,8 +63,8 @@ impl SendPhoto<'_> {
             .add("photo", self.photo);
 
         network::request_multipart(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendPhoto",
             params.build(),
         )
@@ -74,17 +73,13 @@ impl SendPhoto<'_> {
 }
 
 impl<'a> SendPhoto<'a> {
-    pub(crate) fn new<C, P>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        photo: P,
-    ) -> Self
+    pub(crate) fn new<C, P>(bot: &'a Bot, chat_id: C, photo: P) -> Self
     where
         C: Into<ChatId>,
         P: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             photo: photo.into(),
             caption: None,
diff --git a/src/requests/send_poll.rs b/src/requests/send_poll.rs
index 9d8466d3..d5d2e2da 100644
--- a/src/requests/send_poll.rs
+++ b/src/requests/send_poll.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message, ReplyMarkup},
 };
 
@@ -11,7 +12,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct SendPoll<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// identifier for the target chat or username of the target channel (in
     /// the format @channelusername). A native poll can't be sent to a private
     /// chat.
@@ -44,8 +45,8 @@ impl Request for SendPoll<'_> {
 impl SendPoll<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendPoll",
             &self,
         )
@@ -55,7 +56,7 @@ impl SendPoll<'_> {
 
 impl<'a> SendPoll<'a> {
     pub(crate) fn new<C, Q, O>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         chat_id: C,
         question: Q,
         options: O,
@@ -66,7 +67,7 @@ impl<'a> SendPoll<'a> {
         O: Into<Vec<String>>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             question: question.into(),
             options: options.into(),
diff --git a/src/requests/send_venue.rs b/src/requests/send_venue.rs
index 6fdd45e7..30e501c8 100644
--- a/src/requests/send_venue.rs
+++ b/src/requests/send_venue.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, Message, ReplyMarkup},
 };
 
@@ -11,7 +12,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct SendVenue<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or
     /// username of the target channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -59,8 +60,8 @@ impl Request for SendVenue<'_> {
 impl SendVenue<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendVenue",
             &self,
         )
@@ -70,7 +71,7 @@ impl SendVenue<'_> {
 
 impl<'a> SendVenue<'a> {
     pub(crate) fn new<Lt, Lg, C, T, A>(
-        ctx: RequestContext<'a>,
+        bot: &'a Bot,
         chat_id: C,
         latitude: Lt,
         longitude: Lg,
@@ -85,7 +86,7 @@ impl<'a> SendVenue<'a> {
         A: Into<String>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             latitude: latitude.into(),
             longitude: longitude.into(),
diff --git a/src/requests/send_video.rs b/src/requests/send_video.rs
index 5d8d6696..4763fde1 100644
--- a/src/requests/send_video.rs
+++ b/src/requests/send_video.rs
@@ -1,10 +1,12 @@
 use async_trait::async_trait;
 
-use crate::network;
-use crate::requests::{Request, RequestContext, ResponseResult};
-use crate::types::{ChatId, Message, ParseMode, ReplyMarkup};
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
+};
 
-//TODO: add action to bot api
 ///Use this method to send video files, Telegram clients support mp4 videos
 /// (other formats may be sent as Document). On success, the sent Message is
 /// returned. Bots can currently send video files of up to 50 MB in size, this
@@ -12,7 +14,7 @@ use crate::types::{ChatId, Message, ParseMode, ReplyMarkup};
 #[derive(Debug, Clone, Serialize)]
 pub struct SendVideo<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
     pub chat_id: ChatId,
@@ -20,7 +22,7 @@ pub struct SendVideo<'a> {
     /// the Telegram servers (recommended), pass an HTTP URL as a String for
     /// Telegram to get a video from the Internet, or upload a new video using
     /// multipart/form-data. More info on Sending Files »
-    pub video: String,
+    pub video: InputFile,
     ///Duration of sent video in seconds
     #[serde(skip_serializing_if = "Option::is_none")]
     pub duration: Option<u64>,
@@ -39,8 +41,7 @@ pub struct SendVideo<'a> {
     /// if the thumbnail was uploaded using multipart/form-data under
     /// <file_attach_name>. More info on Sending Files »
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub thumb: Option<String>,
-    //InputFile or String
+    pub thumb: Option<InputFile>,
     ///Video caption (may also be used when resending videos by file_id),
     /// 0-1024 characters
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -78,8 +79,8 @@ impl Request for SendVideo<'_> {
 impl SendVideo<'_> {
     async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendVideo",
             &self,
         )
@@ -88,17 +89,13 @@ impl SendVideo<'_> {
 }
 
 impl<'a> SendVideo<'a> {
-    pub(crate) fn new<C, V>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        video: V,
-    ) -> Self
+    pub(crate) fn new<C, V>(bot: &'a Bot, chat_id: C, video: V) -> Self
     where
         C: Into<ChatId>,
-        V: Into<String>,
+        V: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             video: video.into(),
             duration: None,
@@ -123,7 +120,7 @@ impl<'a> SendVideo<'a> {
 
     pub fn video<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.video = value.into();
         self
@@ -152,7 +149,7 @@ impl<'a> SendVideo<'a> {
     }
     pub fn thumb<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.thumb = Some(value.into());
         self
diff --git a/src/requests/send_video_note.rs b/src/requests/send_video_note.rs
index c824bfdf..70e6c9df 100644
--- a/src/requests/send_video_note.rs
+++ b/src/requests/send_video_note.rs
@@ -1,9 +1,10 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
-    types::{ChatId, Message, ReplyMarkup},
+    requests::{Request, ResponseResult},
+    types::{ChatId, InputFile, Message, ReplyMarkup},
 };
 
 ///As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1
@@ -12,7 +13,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct SendVideoNote<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
     pub chat_id: ChatId,
@@ -20,8 +21,7 @@ pub struct SendVideoNote<'a> {
     /// exists on the Telegram servers (recommended) or upload a new video
     /// using multipart/form-data. More info on Sending Files ». Sending video
     /// notes by a URL is currently unsupported
-    pub video_note: String,
-    //	InputFile or String
+    pub video_note: InputFile,
     ///Duration of sent video in seconds
     #[serde(skip_serializing_if = "Option::is_none")]
     pub duration: Option<u64>,
@@ -37,8 +37,7 @@ pub struct SendVideoNote<'a> {
     /// if the thumbnail was uploaded using multipart/form-data under
     /// <file_attach_name>. More info on Sending Files »
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub thumb: Option<String>,
-    //	InputFile or String
+    pub thumb: Option<InputFile>,
     ///Sends the message silently. Users will receive a notification with no
     /// sound.
     #[serde(skip_serializing_if = "Option::is_none")]
@@ -65,8 +64,8 @@ impl Request for SendVideoNote<'_> {
 impl SendVideoNote<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendVideoNote",
             &self,
         )
@@ -75,17 +74,13 @@ impl SendVideoNote<'_> {
 }
 
 impl<'a> SendVideoNote<'a> {
-    pub(crate) fn new<C, V>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        video_note: V,
-    ) -> Self
+    pub(crate) fn new<C, V>(bot: &'a Bot, chat_id: C, video_note: V) -> Self
     where
         C: Into<ChatId>,
-        V: Into<String>,
+        V: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             video_note: video_note.into(),
             duration: None,
@@ -107,7 +102,7 @@ impl<'a> SendVideoNote<'a> {
 
     pub fn video_note<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.video_note = value.into();
         self
@@ -131,7 +126,7 @@ impl<'a> SendVideoNote<'a> {
 
     pub fn thumb<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.thumb = Some(value.into());
         self
diff --git a/src/requests/send_voice.rs b/src/requests/send_voice.rs
index 75f139ea..af3724b9 100644
--- a/src/requests/send_voice.rs
+++ b/src/requests/send_voice.rs
@@ -1,9 +1,10 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
-    types::{ChatId, Message, ParseMode, ReplyMarkup},
+    requests::{Request, ResponseResult},
+    types::{ChatId, InputFile, Message, ParseMode, ReplyMarkup},
 };
 
 ///Use this method to send audio files, if you want Telegram clients to display
@@ -15,7 +16,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct SendVoice<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Unique identifier for the target chat or username of the target channel
     /// (in the format @channelusername)
     pub chat_id: ChatId,
@@ -23,8 +24,7 @@ pub struct SendVoice<'a> {
     /// on the Telegram servers (recommended), pass an HTTP URL as a String for
     /// Telegram to get a file from the Internet, or upload a new one using
     /// multipart/form-data. More info on Sending Files »
-    pub voice: String,
-    //InputFile or String
+    pub voice: InputFile,
     /// Voice message caption, 0-1024 characters
     #[serde(skip_serializing_if = "Option::is_none")]
     pub caption: Option<String>,
@@ -62,8 +62,8 @@ impl Request for SendVoice<'_> {
 impl SendVoice<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "sendVoice",
             &self,
         )
@@ -72,17 +72,13 @@ impl SendVoice<'_> {
 }
 
 impl<'a> SendVoice<'a> {
-    pub(crate) fn new<C, V>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        voice: V,
-    ) -> Self
+    pub(crate) fn new<C, V>(bot: &'a Bot, chat_id: C, voice: V) -> Self
     where
         C: Into<ChatId>,
-        V: Into<String>,
+        V: Into<InputFile>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             voice: voice.into(),
             caption: None,
@@ -104,7 +100,7 @@ impl<'a> SendVoice<'a> {
 
     pub fn voice<T>(mut self, value: T) -> Self
     where
-        T: Into<String>,
+        T: Into<InputFile>,
     {
         self.voice = value.into();
         self
diff --git a/src/requests/set_chat_description.rs b/src/requests/set_chat_description.rs
new file mode 100644
index 00000000..e3cf9c68
--- /dev/null
+++ b/src/requests/set_chat_description.rs
@@ -0,0 +1,99 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, True},
+};
+
+#[derive(Debug, Clone, Serialize)]
+pub struct SetChatDescription<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    chat_id: ChatId,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    description: Option<String>,
+}
+
+#[async_trait]
+impl Request for SetChatDescription<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl SetChatDescription<'_> {
+    pub async fn send(self) -> ResponseResult<True> {
+        network::request_json(
+            &self.bot.client(),
+            &self.bot.token(),
+            "setChatDescription",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> SetChatDescription<'a> {
+    pub(crate) fn new<C>(bot: &'a Bot, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+            description: None,
+        }
+    }
+
+    pub fn chat_id<T>(mut self, chat_id: T) -> Self
+    where
+        T: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+
+    pub fn description<T>(mut self, description: T) -> Self
+    where
+        T: Into<String>,
+    {
+        self.description = Some(description.into());
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize_new() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let method = SetChatDescription::new(&bot, chat_id);
+
+        let expected = r#"{"chat_id":123}"#;
+        let actual =
+            serde_json::to_string::<SetChatDescription>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+
+    #[test]
+    fn serialize_description() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let description = "description";
+        let method =
+            SetChatDescription::new(&bot, chat_id).description(description);
+
+        let expected = r#"{"chat_id":123,"description":"description"}"#;
+        let actual =
+            serde_json::to_string::<SetChatDescription>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
diff --git a/src/requests/set_chat_permissions.rs b/src/requests/set_chat_permissions.rs
new file mode 100644
index 00000000..a7307935
--- /dev/null
+++ b/src/requests/set_chat_permissions.rs
@@ -0,0 +1,96 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, ChatPermissions, True},
+};
+
+#[derive(Debug, Clone, Serialize)]
+pub struct SetChatPermissions<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    chat_id: ChatId,
+    permissions: ChatPermissions,
+}
+
+#[async_trait]
+impl Request for SetChatPermissions<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl SetChatPermissions<'_> {
+    async fn send(self) -> ResponseResult<True> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "setChatPermissions",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> SetChatPermissions<'a> {
+    pub(crate) fn new<C, CP>(bot: &'a Bot, chat_id: C, permissions: CP) -> Self
+    where
+        C: Into<ChatId>,
+        CP: Into<ChatPermissions>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+            permissions: permissions.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+
+    pub fn permissions<CP>(mut self, permissions: CP) -> Self
+    where
+        CP: Into<ChatPermissions>,
+    {
+        self.permissions = permissions.into();
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let permissions = ChatPermissions {
+            can_send_messages: Some(true),
+            can_send_media_messages: None,
+            can_send_polls: None,
+            can_send_other_messages: None,
+            can_add_web_page_previews: None,
+            can_change_info: None,
+            can_invite_users: None,
+            can_pin_messages: None,
+        };
+        let method = SetChatPermissions::new(&bot, chat_id, permissions);
+
+        let expected =
+            r#"{"chat_id":123,"permissions":{"can_send_messages":true}}"#;
+        let actual =
+            serde_json::to_string::<SetChatPermissions>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
diff --git a/src/requests/set_chat_photo.rs b/src/requests/set_chat_photo.rs
new file mode 100644
index 00000000..6a372d1a
--- /dev/null
+++ b/src/requests/set_chat_photo.rs
@@ -0,0 +1,90 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{form_builder::FormBuilder, Request, ResponseResult},
+    types::{ChatId, InputFile, True},
+};
+
+#[derive(Debug, Clone, Serialize)]
+pub struct SetChatPhoto<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    chat_id: ChatId,
+    photo: InputFile,
+}
+
+#[async_trait]
+impl Request for SetChatPhoto<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl SetChatPhoto<'_> {
+    async fn send(self) -> ResponseResult<True> {
+        let params = FormBuilder::new()
+            .add("chat_id", self.chat_id)
+            .add("photo", self.photo);
+
+        network::request_multipart(
+            self.bot.client(),
+            self.bot.token(),
+            "setChatPhoto",
+            params.build(),
+        )
+        .await
+    }
+}
+
+impl<'a> SetChatPhoto<'a> {
+    pub(crate) fn new<C, P>(bot: &'a Bot, chat_id: C, photo: P) -> Self
+    where
+        C: Into<ChatId>,
+        P: Into<InputFile>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+            photo: photo.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+
+    pub fn photo<P>(mut self, photo: P) -> Self
+    where
+        P: Into<InputFile>,
+    {
+        self.photo = photo.into();
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let photo_url = "https://some_url".to_string();
+        let method =
+            SetChatPhoto::new(&bot, chat_id, InputFile::Url(photo_url));
+
+        let expected = r#"{"chat_id":123,"photo":"https://some_url"}"#;
+        let actual = serde_json::to_string::<SetChatPhoto>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
diff --git a/src/requests/set_chat_sticker_set.rs b/src/requests/set_chat_sticker_set.rs
new file mode 100644
index 00000000..a6166cf5
--- /dev/null
+++ b/src/requests/set_chat_sticker_set.rs
@@ -0,0 +1,81 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, True},
+};
+
+/// Use this method to set a new group sticker set for a supergroup. The bot
+/// must be an administrator in the chat for this to work and must have the
+/// appropriate admin rights. Use the field can_set_sticker_set optionally
+/// returned in getChat requests to check if the bot can use this method.
+/// Returns True on success.
+#[derive(Debug, Clone, Serialize)]
+pub struct SetChatStickerSet<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    /// Unique identifier for the target chat or username of the target
+    /// supergroup (in the format @supergroupusername)
+    chat_id: ChatId,
+
+    /// Name of the sticker set to be set as the group sticker set
+    sticker_set_name: String,
+}
+
+#[async_trait]
+impl Request for SetChatStickerSet<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl SetChatStickerSet<'_> {
+    async fn send(&self) -> ResponseResult<True> {
+        network::request_json(
+            self.bot.client(),
+            self.bot.token(),
+            "setChatStickerSet",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> SetChatStickerSet<'a> {
+    pub(crate) fn new<C, S>(
+        bot: &'a Bot,
+        chat_id: C,
+        sticker_set_name: S,
+    ) -> Self
+    where
+        C: Into<ChatId>,
+        S: Into<String>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+            sticker_set_name: sticker_set_name.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, value: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = value.into();
+        self
+    }
+
+    pub fn sticker_set_name<S>(mut self, value: S) -> Self
+    where
+        S: Into<String>,
+    {
+        self.sticker_set_name = value.into();
+        self
+    }
+}
diff --git a/src/requests/set_chat_title.rs b/src/requests/set_chat_title.rs
new file mode 100644
index 00000000..a86f8e2b
--- /dev/null
+++ b/src/requests/set_chat_title.rs
@@ -0,0 +1,85 @@
+use async_trait::async_trait;
+
+use crate::{
+    bot::Bot,
+    network,
+    requests::{Request, ResponseResult},
+    types::{ChatId, True},
+};
+
+#[derive(Debug, Clone, Serialize)]
+pub struct SetChatTitle<'a> {
+    #[serde(skip_serializing)]
+    bot: &'a Bot,
+
+    chat_id: ChatId,
+    title: String,
+}
+
+#[async_trait]
+impl Request for SetChatTitle<'_> {
+    type Output = True;
+
+    async fn send_boxed(self) -> ResponseResult<Self::Output> {
+        self.send().await
+    }
+}
+
+impl SetChatTitle<'_> {
+    async fn send(self) -> ResponseResult<True> {
+        network::request_json(
+            &self.bot.client(),
+            &self.bot.token(),
+            "setChatTitle",
+            &self,
+        )
+        .await
+    }
+}
+
+impl<'a> SetChatTitle<'a> {
+    pub(crate) fn new<C, T>(bot: &'a Bot, chat_id: C, title: T) -> Self
+    where
+        C: Into<ChatId>,
+        T: Into<String>,
+    {
+        Self {
+            bot,
+            chat_id: chat_id.into(),
+            title: title.into(),
+        }
+    }
+
+    pub fn chat_id<C>(mut self, chat_id: C) -> Self
+    where
+        C: Into<ChatId>,
+    {
+        self.chat_id = chat_id.into();
+        self
+    }
+
+    pub fn title<C>(mut self, title: C) -> Self
+    where
+        C: Into<String>,
+    {
+        self.title = title.into();
+        self
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn serialize() {
+        let bot = Bot::new("token");
+        let chat_id = 123;
+        let title = "title";
+        let method = SetChatTitle::new(&bot, chat_id, title);
+
+        let expected = r#"{"chat_id":123,"title":"title"}"#;
+        let actual = serde_json::to_string::<SetChatTitle>(&method).unwrap();
+        assert_eq!(actual, expected);
+    }
+}
diff --git a/src/requests/stop_message_live_location.rs b/src/requests/stop_message_live_location.rs
index 5455944e..7ded4251 100644
--- a/src/requests/stop_message_live_location.rs
+++ b/src/requests/stop_message_live_location.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, InlineKeyboardMarkup, Message},
 };
 
@@ -12,7 +13,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct StopMessageLiveLocation<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     /// Required if inline_message_id is not specified. Unique identifier for
     /// the target chat or username of the target channel (in the format
     /// @channelusername)
@@ -44,8 +45,8 @@ impl Request for StopMessageLiveLocation<'_> {
 impl StopMessageLiveLocation<'_> {
     pub async fn send(self) -> ResponseResult<Message> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "stopMessageLiveLocation",
             &self,
         )
@@ -54,9 +55,9 @@ impl StopMessageLiveLocation<'_> {
 }
 
 impl<'a> StopMessageLiveLocation<'a> {
-    pub(crate) fn new(ctx: RequestContext<'a>) -> Self {
+    pub(crate) fn new(bot: &'a Bot) -> Self {
         Self {
-            ctx,
+            bot,
             chat_id: None,
             message_id: None,
             inline_message_id: None,
diff --git a/src/requests/unban_chat_member.rs b/src/requests/unban_chat_member.rs
index fb772d0d..2af14c12 100644
--- a/src/requests/unban_chat_member.rs
+++ b/src/requests/unban_chat_member.rs
@@ -1,8 +1,9 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::ChatId,
 };
 
@@ -13,7 +14,7 @@ use crate::{
 #[derive(Debug, Clone, Serialize)]
 pub struct UnbanChatMember<'a> {
     #[serde(skip_serializing)]
-    ctx: RequestContext<'a>,
+    bot: &'a Bot,
     ///Unique identifier for the target group or username of the target
     /// supergroup or channel (in the format @channelusername)
     pub chat_id: ChatId,
@@ -33,8 +34,8 @@ impl Request for UnbanChatMember<'_> {
 impl UnbanChatMember<'_> {
     pub async fn send(self) -> ResponseResult<bool> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "unbanChatMember",
             &self,
         )
@@ -43,17 +44,13 @@ impl UnbanChatMember<'_> {
 }
 
 impl<'a> UnbanChatMember<'a> {
-    pub(crate) fn new<C, U>(
-        ctx: RequestContext<'a>,
-        chat_id: C,
-        user_id: U,
-    ) -> Self
+    pub(crate) fn new<C, U>(bot: &'a Bot, chat_id: C, user_id: U) -> Self
     where
         C: Into<ChatId>,
         U: Into<i32>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: chat_id.into(),
             user_id: user_id.into(),
         }
diff --git a/src/requests/unpin_chat_message.rs b/src/requests/unpin_chat_message.rs
index 6bde53d0..1e7f9ef6 100644
--- a/src/requests/unpin_chat_message.rs
+++ b/src/requests/unpin_chat_message.rs
@@ -1,15 +1,16 @@
 use async_trait::async_trait;
 
 use crate::{
+    bot::Bot,
     network,
-    requests::{Request, RequestContext, ResponseResult},
+    requests::{Request, ResponseResult},
     types::{ChatId, True},
 };
 
 #[derive(Debug, Clone, Serialize)]
 pub struct UnpinChatMessage<'a> {
     #[serde(skip_serializing)]
-    pub ctx: RequestContext<'a>,
+    bot: &'a Bot,
 
     pub chat_id: ChatId,
 }
@@ -26,8 +27,8 @@ impl Request for UnpinChatMessage<'_> {
 impl UnpinChatMessage<'_> {
     pub async fn send(self) -> ResponseResult<True> {
         network::request_json(
-            &self.ctx.client,
-            &self.ctx.token,
+            self.bot.client(),
+            self.bot.token(),
             "unpinChatMessage",
             &self,
         )
@@ -36,12 +37,12 @@ impl UnpinChatMessage<'_> {
 }
 
 impl<'a> UnpinChatMessage<'a> {
-    pub(crate) fn new<C>(ctx: RequestContext<'a>, value: C) -> Self
+    pub(crate) fn new<C>(bot: &'a Bot, value: C) -> Self
     where
         C: Into<ChatId>,
     {
         Self {
-            ctx,
+            bot,
             chat_id: value.into(),
         }
     }
diff --git a/src/types/chat_permissions.rs b/src/types/chat_permissions.rs
index 08a5b908..869398aa 100644
--- a/src/types/chat_permissions.rs
+++ b/src/types/chat_permissions.rs
@@ -1,11 +1,19 @@
 #[derive(Debug, Deserialize, Hash, PartialEq, Eq, Serialize, Clone)]
 pub struct ChatPermissions {
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_send_messages: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_send_media_messages: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_send_polls: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_send_other_messages: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_add_web_page_previews: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_change_info: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_invite_users: Option<bool>,
+    #[serde(skip_serializing_if = "Option::is_none")]
     pub can_pin_messages: Option<bool>,
 }
diff --git a/src/types/encrypted_credintials.rs b/src/types/encrypted_credentials.rs
similarity index 100%
rename from src/types/encrypted_credintials.rs
rename to src/types/encrypted_credentials.rs
diff --git a/src/types/encrypted_passport_element.rs b/src/types/encrypted_passport_element.rs
index 425ff429..5788d047 100644
--- a/src/types/encrypted_passport_element.rs
+++ b/src/types/encrypted_passport_element.rs
@@ -1,4 +1,4 @@
-use super::passport_file::PassportFile;
+use super::PassportFile;
 
 #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
 pub struct EncryptedPassportElement {
diff --git a/src/types/inline_keyboard_button.rs b/src/types/inline_keyboard_button.rs
index 27ef8896..935a38c4 100644
--- a/src/types/inline_keyboard_button.rs
+++ b/src/types/inline_keyboard_button.rs
@@ -45,7 +45,7 @@ pub enum InlineKeyboardButtonKind {
 ///
 /// Example:
 /// ```
-/// use async_telegram_bot::types::InlineKeyboardButton;
+/// use telebofr::types::InlineKeyboardButton;
 ///
 /// let url_button = InlineKeyboardButton::url(
 ///     "Text".to_string(),
diff --git a/src/types/inline_keyboard_markup.rs b/src/types/inline_keyboard_markup.rs
index 67bd2aa8..2ca92ee4 100644
--- a/src/types/inline_keyboard_markup.rs
+++ b/src/types/inline_keyboard_markup.rs
@@ -16,9 +16,7 @@ pub struct InlineKeyboardMarkup {
 ///
 /// Example:
 /// ```
-/// use async_telegram_bot::types::{
-///     InlineKeyboardButton, InlineKeyboardMarkup,
-/// };
+/// use telebofr::types::{InlineKeyboardButton, InlineKeyboardMarkup};
 ///
 /// let url_button = InlineKeyboardButton::url(
 ///     "text".to_string(),
diff --git a/src/types/inline_query_result.rs b/src/types/inline_query_result.rs
index f4644b79..098d0dc4 100644
--- a/src/types/inline_query_result.rs
+++ b/src/types/inline_query_result.rs
@@ -49,9 +49,8 @@ pub enum InlineQueryResult {
 
 #[cfg(test)]
 mod tests {
-    use crate::types::inline_keyboard_markup::InlineKeyboardMarkup;
-    use crate::types::parse_mode::ParseMode;
     use crate::types::{
+        inline_keyboard_markup::InlineKeyboardMarkup, parse_mode::ParseMode,
         InlineQueryResult, InlineQueryResultCachedAudio, InputMessageContent,
     };
 
diff --git a/src/types/keyboard_button.rs b/src/types/keyboard_button.rs
index 41d1b156..01929838 100644
--- a/src/types/keyboard_button.rs
+++ b/src/types/keyboard_button.rs
@@ -1,4 +1,4 @@
-/// This object represents one button of the reply keyboard. For simple text
+/// This object represents one button of the reply keyboard. For filter text
 /// buttons String can be used instead of this object to specify text of the
 /// button. Optional fields are mutually exclusive.
 #[derive(Debug, Serialize, Deserialize, Hash, PartialEq, Eq, Clone)]
diff --git a/src/types/message.rs b/src/types/message.rs
index c658dd42..61bebed0 100644
--- a/src/types/message.rs
+++ b/src/types/message.rs
@@ -1,4 +1,8 @@
-use crate::types::{Animation, Audio, Chat, Contact, Document, Game, InlineKeyboardMarkup, Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, Sticker, SuccessfulPayment, User, Venue, Video, VideoNote, Voice, True};
+use crate::types::{
+    Animation, Audio, Chat, Contact, Document, Game, InlineKeyboardMarkup,
+    Invoice, Location, MessageEntity, PassportData, PhotoSize, Poll, Sticker,
+    SuccessfulPayment, True, User, Venue, Video, VideoNote, Voice,
+};
 
 #[derive(Debug, Deserialize, PartialEq, Clone)]
 pub struct Message {
@@ -10,7 +14,6 @@ pub struct Message {
     pub kind: MessageKind,
 }
 
-
 #[derive(Debug, Deserialize, PartialEq, Clone)]
 #[serde(untagged)]
 pub enum MessageKind {
@@ -188,23 +191,23 @@ mod getters {
     use std::ops::Deref;
 
     use crate::types::{
-        self, Message, Sender, User, ForwardedFrom, Chat, MessageEntity,
-        PhotoSize, True,
+        self,
         message::{
-            MessageKind::{
-                Common, NewChatMembers, LeftChatMember, NewChatTitle,
-                NewChatPhoto, DeleteChatPhoto, GroupChatCreated,
-                ChannelChatCreated, Migrate, Invoice, SuccessfulPayment,
-                ConnectedWebsite, PassportData
-            },
+            ForwardKind::{ChannelForward, NonChannelForward, Origin},
             MediaKind::{
-                Text, Video, Photo, Animation, Audio, Document, Voice, Game,
-                Sticker, VideoNote, Contact, Location, Poll, Venue
+                Animation, Audio, Contact, Document, Game, Location, Photo,
+                Poll, Sticker, Text, Venue, Video, VideoNote, Voice,
+            },
+            MessageKind::{
+                ChannelChatCreated, Common, ConnectedWebsite, DeleteChatPhoto,
+                GroupChatCreated, Invoice, LeftChatMember, Migrate,
+                NewChatMembers, NewChatPhoto, NewChatTitle, PassportData,
+                Pinned, SuccessfulPayment, SupergroupChatCreated,
             },
-            ForwardKind::{NonChannelForward, ChannelForward, Origin}
         },
+        Chat, ForwardedFrom, Message, MessageEntity, PhotoSize, Sender, True,
+        User,
     };
-    use crate::types::message::MessageKind::{SupergroupChatCreated, Pinned};
 
     /// Getters for [Message] fields from [telegram docs].
     ///
@@ -223,49 +226,67 @@ mod getters {
         /// `forward_sender_name`
         pub fn forward_from(&self) -> Option<&ForwardedFrom> {
             match &self.kind {
-                Common { forward_kind: NonChannelForward { from, .. }, .. } =>
-                    Some(from),
+                Common {
+                    forward_kind: NonChannelForward { from, .. },
+                    ..
+                } => Some(from),
                 _ => None,
             }
         }
 
         pub fn forward_from_chat(&self) -> Option<&Chat> {
             match &self.kind {
-                Common { forward_kind: ChannelForward { chat, .. }, .. } =>
-                    Some(chat),
+                Common {
+                    forward_kind: ChannelForward { chat, .. },
+                    ..
+                } => Some(chat),
                 _ => None,
             }
         }
 
         pub fn forward_from_message_id(&self) -> Option<&i32> {
             match &self.kind {
-                Common { forward_kind: ChannelForward { message_id, .. }, .. } =>
-                    Some(message_id),
+                Common {
+                    forward_kind: ChannelForward { message_id, .. },
+                    ..
+                } => Some(message_id),
                 _ => None,
             }
         }
 
         pub fn forward_signature(&self) -> Option<&str> {
             match &self.kind {
-                Common { forward_kind: ChannelForward { signature, .. }, .. } =>
-                    signature.as_ref().map(Deref::deref),
+                Common {
+                    forward_kind: ChannelForward { signature, .. },
+                    ..
+                } => signature.as_ref().map(Deref::deref),
                 _ => None,
             }
         }
 
         pub fn forward_date(&self) -> Option<&i32> {
             match &self.kind {
-                Common { forward_kind: ChannelForward { date, .. }, .. } |
-                Common { forward_kind: NonChannelForward { date, .. }, .. } =>
-                    Some(date),
+                Common {
+                    forward_kind: ChannelForward { date, .. },
+                    ..
+                }
+                | Common {
+                    forward_kind: NonChannelForward { date, .. },
+                    ..
+                } => Some(date),
                 _ => None,
             }
         }
 
         pub fn reply_to_message(&self) -> Option<&Message> {
             match &self.kind {
-                Common { forward_kind: Origin { reply_to_message, .. }, .. } =>
-                    reply_to_message.as_ref().map(Deref::deref),
+                Common {
+                    forward_kind:
+                        Origin {
+                            reply_to_message, ..
+                        },
+                    ..
+                } => reply_to_message.as_ref().map(Deref::deref),
                 _ => None,
             }
         }
@@ -279,104 +300,172 @@ mod getters {
 
         pub fn media_group_id(&self) -> Option<&str> {
             match &self.kind {
-                Common { media_kind: Video { media_group_id, .. }, .. } |
-                Common { media_kind: Photo { media_group_id, .. }, .. } =>
-                    media_group_id.as_ref().map(Deref::deref),
+                Common {
+                    media_kind: Video { media_group_id, .. },
+                    ..
+                }
+                | Common {
+                    media_kind: Photo { media_group_id, .. },
+                    ..
+                } => media_group_id.as_ref().map(Deref::deref),
                 _ => None,
             }
         }
 
         pub fn text(&self) -> Option<&str> {
             match &self.kind {
-                Common { media_kind: Text { text, .. }, .. } => Some(text),
+                Common {
+                    media_kind: Text { text, .. },
+                    ..
+                } => Some(text),
                 _ => None,
             }
         }
 
         pub fn entities(&self) -> Option<&[MessageEntity]> {
             match &self.kind {
-                Common { media_kind: Text { entities, .. }, .. } =>
-                    Some(entities),
+                Common {
+                    media_kind: Text { entities, .. },
+                    ..
+                } => Some(entities),
                 _ => None,
             }
         }
 
         pub fn caption_entities(&self) -> Option<&[MessageEntity]> {
             match &self.kind {
-                Common { media_kind: Animation { caption_entities, .. }, .. } |
-                Common { media_kind: Audio { caption_entities, .. }, .. } |
-                Common { media_kind: Document { caption_entities, .. }, .. } |
-                Common { media_kind: Photo { caption_entities, .. }, .. } |
-                Common { media_kind: Video { caption_entities, .. }, .. } |
-                Common { media_kind: Voice { caption_entities, .. }, .. } =>
-                    Some(caption_entities),
+                Common {
+                    media_kind:
+                        Animation {
+                            caption_entities, ..
+                        },
+                    ..
+                }
+                | Common {
+                    media_kind:
+                        Audio {
+                            caption_entities, ..
+                        },
+                    ..
+                }
+                | Common {
+                    media_kind:
+                        Document {
+                            caption_entities, ..
+                        },
+                    ..
+                }
+                | Common {
+                    media_kind:
+                        Photo {
+                            caption_entities, ..
+                        },
+                    ..
+                }
+                | Common {
+                    media_kind:
+                        Video {
+                            caption_entities, ..
+                        },
+                    ..
+                }
+                | Common {
+                    media_kind:
+                        Voice {
+                            caption_entities, ..
+                        },
+                    ..
+                } => Some(caption_entities),
                 _ => None,
             }
         }
 
         pub fn audio(&self) -> Option<&types::Audio> {
             match &self.kind {
-                Common { media_kind: Audio { audio, .. }, .. } => Some(audio),
+                Common {
+                    media_kind: Audio { audio, .. },
+                    ..
+                } => Some(audio),
                 _ => None,
             }
         }
 
         pub fn document(&self) -> Option<&types::Document> {
             match &self.kind {
-                Common { media_kind: Document { document, .. }, .. } =>
-                    Some(document),
+                Common {
+                    media_kind: Document { document, .. },
+                    ..
+                } => Some(document),
                 _ => None,
             }
         }
 
         pub fn animation(&self) -> Option<&types::Animation> {
             match &self.kind {
-                Common { media_kind: Animation { animation, .. }, .. } =>
-                    Some(animation),
+                Common {
+                    media_kind: Animation { animation, .. },
+                    ..
+                } => Some(animation),
                 _ => None,
             }
         }
 
         pub fn game(&self) -> Option<&types::Game> {
             match &self.kind {
-                Common { media_kind: Game { game, .. }, .. } => Some(game),
+                Common {
+                    media_kind: Game { game, .. },
+                    ..
+                } => Some(game),
                 _ => None,
             }
         }
 
         pub fn photo(&self) -> Option<&[PhotoSize]> {
             match &self.kind {
-                Common { media_kind: Photo { photo, .. }, .. } => Some(photo),
+                Common {
+                    media_kind: Photo { photo, .. },
+                    ..
+                } => Some(photo),
                 _ => None,
             }
         }
 
         pub fn sticker(&self) -> Option<&types::Sticker> {
             match &self.kind {
-                Common { media_kind: Sticker { sticker, .. }, .. } =>
-                    Some(sticker),
+                Common {
+                    media_kind: Sticker { sticker, .. },
+                    ..
+                } => Some(sticker),
                 _ => None,
             }
         }
 
         pub fn video(&self) -> Option<&types::Video> {
             match &self.kind {
-                Common { media_kind: Video { video, .. }, .. } => Some(video),
+                Common {
+                    media_kind: Video { video, .. },
+                    ..
+                } => Some(video),
                 _ => None,
             }
         }
 
         pub fn voice(&self) -> Option<&types::Voice> {
             match &self.kind {
-                Common { media_kind: Voice { voice, .. }, .. } => Some(voice),
+                Common {
+                    media_kind: Voice { voice, .. },
+                    ..
+                } => Some(voice),
                 _ => None,
             }
         }
 
         pub fn video_note(&self) -> Option<&types::VideoNote> {
             match &self.kind {
-                Common { media_kind: VideoNote { video_note, .. }, .. } =>
-                    Some(video_note),
+                Common {
+                    media_kind: VideoNote { video_note, .. },
+                    ..
+                } => Some(video_note),
                 _ => None,
             }
         }
@@ -384,12 +473,14 @@ mod getters {
         pub fn caption(&self) -> Option<&str> {
             match &self.kind {
                 Common { media_kind, .. } => match media_kind {
-                    Animation { caption, ..} |
-                    Audio { caption, ..} |
-                    Document { caption, ..} |
-                    Photo { caption, ..} |
-                    Video { caption, ..} |
-                    Voice { caption, ..} => caption.as_ref().map(Deref::deref),
+                    Animation { caption, .. }
+                    | Audio { caption, .. }
+                    | Document { caption, .. }
+                    | Photo { caption, .. }
+                    | Video { caption, .. }
+                    | Voice { caption, .. } => {
+                        caption.as_ref().map(Deref::deref)
+                    }
                     _ => None,
                 },
                 _ => None,
@@ -398,29 +489,40 @@ mod getters {
 
         pub fn contact(&self) -> Option<&types::Contact> {
             match &self.kind {
-                Common { media_kind: Contact { contact }, .. } => Some(contact),
+                Common {
+                    media_kind: Contact { contact },
+                    ..
+                } => Some(contact),
                 _ => None,
             }
         }
 
         pub fn location(&self) -> Option<&types::Location> {
             match &self.kind {
-                Common { media_kind: Location { location, .. }, .. } =>
-                    Some(location),
+                Common {
+                    media_kind: Location { location, .. },
+                    ..
+                } => Some(location),
                 _ => None,
             }
         }
 
         pub fn venue(&self) -> Option<&types::Venue> {
             match &self.kind {
-                Common { media_kind: Venue { venue, .. }, .. } => Some(venue),
+                Common {
+                    media_kind: Venue { venue, .. },
+                    ..
+                } => Some(venue),
                 _ => None,
             }
         }
 
         pub fn poll(&self) -> Option<&types::Poll> {
             match &self.kind {
-                Common { media_kind: Poll { poll, .. }, .. } => Some(poll),
+                Common {
+                    media_kind: Poll { poll, .. },
+                    ..
+                } => Some(poll),
                 _ => None,
             }
         }
@@ -457,47 +559,55 @@ mod getters {
         //       mb smt like `is_delete_chat_photo(&self) -> bool`?
         pub fn delete_chat_photo(&self) -> Option<True> {
             match &self.kind {
-                DeleteChatPhoto { delete_chat_photo } =>
-                    Some(*delete_chat_photo),
+                DeleteChatPhoto { delete_chat_photo } => {
+                    Some(*delete_chat_photo)
+                }
                 _ => None,
             }
         }
 
         pub fn group_chat_created(&self) -> Option<True> {
             match &self.kind {
-                GroupChatCreated { group_chat_created } =>
-                    Some(*group_chat_created),
+                GroupChatCreated { group_chat_created } => {
+                    Some(*group_chat_created)
+                }
                 _ => None,
             }
         }
 
         pub fn super_group_chat_created(&self) -> Option<True> {
             match &self.kind {
-                SupergroupChatCreated { supergroup_chat_created } =>
-                    Some(*supergroup_chat_created),
+                SupergroupChatCreated {
+                    supergroup_chat_created,
+                } => Some(*supergroup_chat_created),
                 _ => None,
             }
         }
 
         pub fn channel_chat_created(&self) -> Option<True> {
             match &self.kind {
-                ChannelChatCreated { channel_chat_created } =>
-                    Some(*channel_chat_created),
+                ChannelChatCreated {
+                    channel_chat_created,
+                } => Some(*channel_chat_created),
                 _ => None,
             }
         }
 
         pub fn migrate_to_chat_id(&self) -> Option<&i64> {
             match &self.kind {
-                Migrate { migrate_to_chat_id, .. } => Some(migrate_to_chat_id),
+                Migrate {
+                    migrate_to_chat_id, ..
+                } => Some(migrate_to_chat_id),
                 _ => None,
             }
         }
 
         pub fn migrate_from_chat_id(&self) -> Option<&i64> {
             match &self.kind {
-                Migrate { migrate_from_chat_id, .. } =>
-                    Some(migrate_from_chat_id),
+                Migrate {
+                    migrate_from_chat_id,
+                    ..
+                } => Some(migrate_from_chat_id),
                 _ => None,
             }
         }
@@ -516,25 +626,24 @@ mod getters {
             }
         }
 
-
         pub fn successful_payment(&self) -> Option<&types::SuccessfulPayment> {
             match &self.kind {
-                SuccessfulPayment { successful_payment } =>
-                    Some(successful_payment),
+                SuccessfulPayment { successful_payment } => {
+                    Some(successful_payment)
+                }
                 _ => None,
             }
         }
 
-
         pub fn connected_website(&self) -> Option<&str> {
             match &self.kind {
-                ConnectedWebsite { connected_website } =>
-                    Some(connected_website),
+                ConnectedWebsite { connected_website } => {
+                    Some(connected_website)
+                }
                 _ => None,
             }
         }
 
-
         pub fn passport_data(&self) -> Option<&types::PassportData> {
             match &self.kind {
                 PassportData { passport_data } => Some(passport_data),
@@ -542,7 +651,6 @@ mod getters {
             }
         }
 
-
         pub fn reply_markup(&self) -> Option<&types::InlineKeyboardMarkup> {
             match &self.kind {
                 Common { reply_markup, .. } => reply_markup.as_ref(),
@@ -552,7 +660,6 @@ mod getters {
     }
 }
 
-
 #[cfg(test)]
 mod tests {
     use serde_json::from_str;
diff --git a/src/types/mod.rs b/src/types/mod.rs
index b3268627..075b1dfc 100644
--- a/src/types/mod.rs
+++ b/src/types/mod.rs
@@ -1,92 +1,87 @@
-//! Raw API structures.
+//! API types.
 
-pub use self::{
-    animation::Animation,
-    audio::Audio,
-    callback_game::CallbackGame,
-    callback_query::CallbackQuery,
-    chat::{Chat, ChatKind, NonPrivateChatKind},
-    chat_action::ChatAction,
-    chat_id::ChatId,
-    chat_member::{ChatMember, ChatMemberStatus},
-    chat_permissions::ChatPermissions,
-    chat_photo::ChatPhoto,
-    chosen_inline_result::ChosenInlineResult,
-    contact::Contact,
-    document::Document,
-    encrypted_credintials::EncryptedCredentials,
-    encrypted_passport_element::{
-        EncryptedPassportElement, EncryptedPassportElementKind,
-    },
-    file::File,
-    force_reply::ForceReply,
-    game::Game,
-    game_high_score::GameHighScore,
-    inline_keyboard_button::{InlineKeyboardButton, InlineKeyboardButtonKind},
-    inline_keyboard_markup::InlineKeyboardMarkup,
-    inline_query::InlineQuery,
-    inline_query_result::InlineQueryResult,
-    inline_query_result_article::InlineQueryResultArticle,
-    inline_query_result_audio::InlineQueryResultAudio,
-    inline_query_result_cached_audio::InlineQueryResultCachedAudio,
-    inline_query_result_cached_document::InlineQueryResultCachedDocument,
-    inline_query_result_cached_gif::InlineQueryResultCachedGif,
-    inline_query_result_cached_mpeg4_gif::InlineQueryResultCachedMpeg4Gif,
-    inline_query_result_cached_photo::InlineQueryResultCachedPhoto,
-    inline_query_result_cached_sticker::InlineQueryResultCachedSticker,
-    inline_query_result_cached_video::InlineQueryResultCachedVideo,
-    inline_query_result_cached_voice::InlineQueryResultCachedVoice,
-    inline_query_result_contact::InlineQueryResultContact,
-    inline_query_result_document::InlineQueryResultDocument,
-    inline_query_result_game::InlineQueryResultGame,
-    inline_query_result_gif::InlineQueryResultGif,
-    inline_query_result_location::InlineQueryResultLocation,
-    inline_query_result_mpeg4_gif::InlineQueryResultMpeg4Gif,
-    inline_query_result_photo::InlineQueryResultPhoto,
-    inline_query_result_venue::InlineQueryResultVenue,
-    inline_query_result_video::InlineQueryResultVideo,
-    inline_query_result_voice::InlineQueryResultVoice,
-    input_file::InputFile,
-    input_media::InputMedia,
-    input_message_content::InputMessageContent,
-    invoice::Invoice,
-    keyboard_button::KeyboardButton,
-    label_price::LabeledPrice,
-    location::Location,
-    login_url::LoginUrl,
-    mask_position::MaskPosition,
-    message::{
-        ForwardKind, ForwardedFrom, MediaKind, Message, MessageKind, Sender,
-    },
-    message_entity::MessageEntity,
-    order_info::OrderInfo,
-    parse_mode::ParseMode,
-    passport_data::PassportData,
-    passport_file::PassportFile,
-    photo_size::PhotoSize,
-    poll::{Poll, PollOption},
-    pre_checkout_query::PreCheckoutQuery,
-    reply_keyboard_markup::ReplyKeyboardMarkup,
-    reply_keyboard_remove::ReplyKeyboardRemove,
-    reply_markup::ReplyMarkup,
-    response_parameters::ResponseParameters,
-    send_invoice::SendInvoice,
-    shipping_address::ShippingAddress,
-    shipping_option::ShippingOption,
-    shipping_query::ShippingQuery,
-    sticker::Sticker,
-    sticker_set::StickerSet,
-    successful_payment::SuccessfulPayment,
-    unit_true::True,
-    update::{Update, UpdateKind},
-    user::User,
-    user_profile_photos::UserProfilePhotos,
-    venue::Venue,
-    video::Video,
-    video_note::VideoNote,
-    voice::Voice,
-    webhook_info::WebhookInfo,
-};
+pub use animation::*;
+pub use audio::*;
+pub use callback_game::*;
+pub use callback_query::*;
+pub use chat::*;
+pub use chat_action::*;
+pub use chat_id::*;
+pub use chat_member::*;
+pub use chat_permissions::*;
+pub use chat_photo::*;
+pub use chosen_inline_result::*;
+pub use contact::*;
+pub use document::*;
+pub use encrypted_credentials::*;
+pub use encrypted_passport_element::*;
+pub use file::*;
+pub use force_reply::*;
+pub use game::*;
+pub use game_high_score::*;
+pub use inline_keyboard_button::*;
+pub use inline_keyboard_markup::*;
+pub use inline_query::*;
+pub use inline_query_result::*;
+pub use inline_query_result_article::*;
+pub use inline_query_result_audio::*;
+pub use inline_query_result_cached_audio::*;
+pub use inline_query_result_cached_document::*;
+pub use inline_query_result_cached_gif::*;
+pub use inline_query_result_cached_mpeg4_gif::*;
+pub use inline_query_result_cached_photo::*;
+pub use inline_query_result_cached_sticker::*;
+pub use inline_query_result_cached_video::*;
+pub use inline_query_result_cached_voice::*;
+pub use inline_query_result_contact::*;
+pub use inline_query_result_document::*;
+pub use inline_query_result_game::*;
+pub use inline_query_result_gif::*;
+pub use inline_query_result_location::*;
+pub use inline_query_result_mpeg4_gif::*;
+pub use inline_query_result_photo::*;
+pub use inline_query_result_venue::*;
+pub use inline_query_result_video::*;
+pub use inline_query_result_voice::*;
+pub use input_file::*;
+pub use input_media::*;
+pub use input_message_content::*;
+pub use invoice::*;
+pub use keyboard_button::*;
+pub use label_price::*;
+pub use location::*;
+pub use login_url::*;
+pub use mask_position::*;
+pub use message::*;
+pub use message_entity::*;
+pub use order_info::*;
+pub use parse_mode::*;
+pub use passport_data::*;
+pub use passport_file::*;
+pub use photo_size::*;
+pub use poll::*;
+pub use pre_checkout_query::*;
+pub use reply_keyboard_markup::*;
+pub use reply_keyboard_remove::*;
+pub use reply_markup::*;
+pub use response_parameters::*;
+pub use send_invoice::*;
+pub use shipping_address::*;
+pub use shipping_option::*;
+pub use shipping_query::*;
+pub use sticker::*;
+pub use sticker_set::*;
+pub use successful_payment::*;
+pub use unit_false::*;
+pub use unit_true::*;
+pub use update::*;
+pub use user::*;
+pub use user_profile_photos::*;
+pub use venue::*;
+pub use video::*;
+pub use video_note::*;
+pub use voice::*;
+pub use webhook_info::*;
 
 mod animation;
 mod audio;
@@ -134,6 +129,7 @@ mod shipping_query;
 mod sticker;
 mod sticker_set;
 mod successful_payment;
+mod unit_false;
 mod unit_true;
 mod update;
 mod user;
@@ -167,7 +163,7 @@ mod inline_query_result_venue;
 mod inline_query_result_video;
 mod inline_query_result_voice;
 
-mod encrypted_credintials;
+mod encrypted_credentials;
 mod encrypted_passport_element;
 mod passport_data;
 mod passport_file;
diff --git a/src/types/passport_data.rs b/src/types/passport_data.rs
index 8ca8e20c..4c938af8 100644
--- a/src/types/passport_data.rs
+++ b/src/types/passport_data.rs
@@ -1,5 +1,4 @@
-use super::encrypted_credintials::EncryptedCredentials;
-use super::encrypted_passport_element::EncryptedPassportElement;
+use super::{EncryptedCredentials, EncryptedPassportElement};
 
 #[derive(Debug, Deserialize, Eq, Hash, PartialEq, Clone, Serialize)]
 pub struct PassportData {
diff --git a/src/types/unit_false.rs b/src/types/unit_false.rs
new file mode 100644
index 00000000..f5039f8e
--- /dev/null
+++ b/src/types/unit_false.rs
@@ -0,0 +1,80 @@
+use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
+
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)]
+pub struct False;
+
+impl std::convert::TryFrom<bool> for False {
+    type Error = ();
+
+    fn try_from(value: bool) -> Result<Self, Self::Error> {
+        #[allow(clippy::match_bool)]
+        match value {
+            true => Err(()),
+            false => Ok(False),
+        }
+    }
+}
+
+impl<'de> Deserialize<'de> for False {
+    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+    where
+        D: Deserializer<'de>,
+    {
+        deserializer.deserialize_bool(FalseVisitor)
+    }
+}
+
+struct FalseVisitor;
+
+impl<'de> Visitor<'de> for FalseVisitor {
+    type Value = False;
+
+    fn expecting(
+        &self,
+        formatter: &mut std::fmt::Formatter,
+    ) -> std::fmt::Result {
+        write!(formatter, "bool, equal to `false`")
+    }
+
+    fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
+    where
+        E: serde::de::Error,
+    {
+        #[allow(clippy::match_bool)]
+        match value {
+            true => Err(E::custom("expected `false`, found `true`")),
+            false => Ok(False),
+        }
+    }
+}
+
+impl Serialize for False {
+    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+    {
+        serializer.serialize_bool(false)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use serde_json::{from_str, to_string};
+
+    use super::False;
+
+    #[test]
+    fn unit_false_de() {
+        let json = "false";
+        let expected = False;
+        let actual = from_str(json).unwrap();
+        assert_eq!(expected, actual);
+    }
+
+    #[test]
+    fn unit_false_se() {
+        let actual = to_string(&False).unwrap();
+        let expected = "false";
+        assert_eq!(expected, actual);
+    }
+}
diff --git a/src/types/unit_true.rs b/src/types/unit_true.rs
index 0efe1b33..ed953d46 100644
--- a/src/types/unit_true.rs
+++ b/src/types/unit_true.rs
@@ -1,7 +1,9 @@
-use serde::de::{self, Deserialize, Deserializer, Visitor};
-use serde::ser::{Serialize, Serializer};
+use serde::{
+    de::{self, Deserialize, Deserializer, Visitor},
+    ser::{Serialize, Serializer},
+};
 
-#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, Default, Eq, Hash, PartialEq)]
 pub struct True;
 
 impl std::convert::TryFrom<bool> for True {