Repository: python-telegram-bot/python-telegram-bot
Pull request: Introducing Api 5.1
When merged, this closes #2423.

Open questions:

- [x] Should two ChatInviteLinks be equal, when the invite link and creator are equal, or in some other scenario?


### Checklist for PRs

- [x] Added `.. versionadded:: version`, `.. versionchanged:: version` or `.. deprecated:: version` to the docstrings for user facing changes (for methods/class descriptions, arguments and attributes)

### If the PR contains API changes (otherwise, you can delete this passage)

* New classes:
    - [x] Added `self._id_attrs` and corresponding documentation
    - [x] `__init__` accepts `**_kwargs`
    
* Added new / updated shortcuts:
    - [x] In `Chat` & `User` for all methods that accept `chat/user_id`
    - ~[ ] In `Message` for all methods that accept `chat_id` and `message_id`~
    - ~[ ] For new `Message` shortcuts: Added `quote` argument if methods accepts `reply_to_message_id`~
    - ~[ ] In `CallbackQuery` for all methods that accept either `chat_id` and `message_id` or `inline_message_id`~
    
* If relevant:

    - [x] Added new constants at `telegram.constants` and shortcuts to them as class variables
    - [x] Added new handlers for new update types
    - [x] Added new filters for new message (sub)types
    - [x] Added or updated documentation for the changed class(es) and/or method(s)
    - [x] Updated the Bot API version number in all places in `README.rst` and `README_RAW.rst`, including the badge


Active docs build is at https://python-telegram-bot.readthedocs.io/en/api_5.1/

Problem statement:
[FEATURE] API 5.1 support
It's a bright new world, and a bright new update.

### Two new update types + stuff @Bibo-Joshi 

- [x] ChatMemberUpdated
- [x] add two for this to Update
- [x] add to effective_chat
- [x] add to effective_user
- [x] MessageAutoDeleteTimerChanged  + attribute to message

### Invite Links @Poolitzer 

- [x] ChatInviteLink
- [x] createChatInviteLink
- [x] editChatInviteLink
- [x] revokeChatInviteLink
- [x] change description of the original InviteLink method

### Voice chat info @starry69 

- [x] VoiceChatStarted 
- [x] VoiceChatEnded
- [x] VoiceChatParticipantsInvited
- [x] all three to Message
- [x] ChatMember has a new attribute, can_manage_voice_chats 
- [x] promoteChatMember has the corresponding parameter

### And more @harshil21 
- [x] InlinequeryResult has a new note
- [x] revoke_messages for kickChatMember to delete all messages from the user
- [x] can_manage_chat  as attribute to ChatMember and promoteChatMember
- [x] bowling dice animation YEAH!

Hints from issue discussion:

Commit message: fix: changing equality of chatinviteobjects

Patch to review:
diff --git a/docs/source/telegram.chatinvitelink.rst b/docs/source/telegram.chatinvitelink.rst
new file mode 100644
index 00000000000..ca24e5340ba
--- /dev/null
+++ b/docs/source/telegram.chatinvitelink.rst
@@ -0,0 +1,6 @@
+telegram.ChatInviteLink
+=======================
+
+.. autoclass:: telegram.ChatInviteLink
+    :members:
+    :show-inheritance:
diff --git a/docs/source/telegram.chatmemberupdated.rst b/docs/source/telegram.chatmemberupdated.rst
new file mode 100644
index 00000000000..d6feecc442f
--- /dev/null
+++ b/docs/source/telegram.chatmemberupdated.rst
@@ -0,0 +1,6 @@
+telegram.ChatMemberUpdated
+==========================
+
+.. autoclass:: telegram.ChatMemberUpdated
+    :members:
+    :show-inheritance:
diff --git a/docs/source/telegram.ext.chatmemberhandler.rst b/docs/source/telegram.ext.chatmemberhandler.rst
new file mode 100644
index 00000000000..59675b9547a
--- /dev/null
+++ b/docs/source/telegram.ext.chatmemberhandler.rst
@@ -0,0 +1,6 @@
+telegram.ext.ChatMemberHandler
+==============================
+
+.. autoclass:: telegram.ext.ChatMemberHandler
+    :members:
+    :show-inheritance:
diff --git a/docs/source/telegram.ext.rst b/docs/source/telegram.ext.rst
index 8bd50adcb30..9bd855a877f 100644
--- a/docs/source/telegram.ext.rst
+++ b/docs/source/telegram.ext.rst
@@ -21,6 +21,7 @@ Handlers
     telegram.ext.handler
     telegram.ext.callbackqueryhandler
     telegram.ext.choseninlineresulthandler
+    telegram.ext.chatmemberhandler
     telegram.ext.commandhandler
     telegram.ext.conversationhandler
     telegram.ext.inlinequeryhandler
diff --git a/docs/source/telegram.messageautodeletetimerchanged.rst b/docs/source/telegram.messageautodeletetimerchanged.rst
new file mode 100644
index 00000000000..ae1fd5472f6
--- /dev/null
+++ b/docs/source/telegram.messageautodeletetimerchanged.rst
@@ -0,0 +1,6 @@
+telegram.MessageAutoDeleteTimerChanged
+======================================
+
+.. autoclass:: telegram.MessageAutoDeleteTimerChanged
+    :members:
+    :show-inheritance:
diff --git a/docs/source/telegram.rst b/docs/source/telegram.rst
index daa1f96569e..f0817a6060c 100644
--- a/docs/source/telegram.rst
+++ b/docs/source/telegram.rst
@@ -13,8 +13,10 @@ telegram package
     telegram.callbackquery
     telegram.chat
     telegram.chataction
+    telegram.chatinvitelink
     telegram.chatlocation
     telegram.chatmember
+    telegram.chatmemberupdated
     telegram.chatpermissions
     telegram.chatphoto
     telegram.constants
@@ -38,6 +40,7 @@ telegram package
     telegram.location
     telegram.loginurl
     telegram.message
+    telegram.messageautodeletetimerchanged
     telegram.messageid
     telegram.messageentity
     telegram.parsemode
@@ -57,6 +60,9 @@ telegram package
     telegram.video
     telegram.videonote
     telegram.voice
+    telegram.voicechatstarted
+    telegram.voicechatended
+    telegram.voicechatparticipantsinvited
     telegram.webhookinfo
 
 Stickers
diff --git a/docs/source/telegram.voicechatended.rst b/docs/source/telegram.voicechatended.rst
new file mode 100644
index 00000000000..1183f632fc8
--- /dev/null
+++ b/docs/source/telegram.voicechatended.rst
@@ -0,0 +1,7 @@
+telegram.VoiceChatEnded
+=======================
+
+.. autoclass:: telegram.VoiceChatEnded
+    :members:
+    :show-inheritance:
+
diff --git a/docs/source/telegram.voicechatparticipantsinvited.rst b/docs/source/telegram.voicechatparticipantsinvited.rst
new file mode 100644
index 00000000000..c2e70a9a837
--- /dev/null
+++ b/docs/source/telegram.voicechatparticipantsinvited.rst
@@ -0,0 +1,7 @@
+telegram.VoiceChatParticipantsInvited
+=====================================
+
+.. autoclass:: telegram.VoiceChatParticipantsInvited
+    :members:
+    :show-inheritance:
+
diff --git a/docs/source/telegram.voicechatstarted.rst b/docs/source/telegram.voicechatstarted.rst
new file mode 100644
index 00000000000..31981b95afe
--- /dev/null
+++ b/docs/source/telegram.voicechatstarted.rst
@@ -0,0 +1,7 @@
+telegram.VoiceChatStarted
+=========================
+
+.. autoclass:: telegram.VoiceChatStarted
+    :members:
+    :show-inheritance:
+
diff --git a/telegram/__init__.py b/telegram/__init__.py
index f1dc551c496..b7c14fd443c 100644
--- a/telegram/__init__.py
+++ b/telegram/__init__.py
@@ -24,7 +24,9 @@
 from .files.chatphoto import ChatPhoto
 from .chat import Chat
 from .chatlocation import ChatLocation
+from .chatinvitelink import ChatInviteLink
 from .chatmember import ChatMember
+from .chatmemberupdated import ChatMemberUpdated
 from .chatpermissions import ChatPermissions
 from .files.photosize import PhotoSize
 from .files.audio import Audio
@@ -54,6 +56,7 @@
 from .messageid import MessageId
 from .games.game import Game
 from .poll import Poll, PollOption, PollAnswer
+from .voicechat import VoiceChatStarted, VoiceChatEnded, VoiceChatParticipantsInvited
 from .loginurl import LoginUrl
 from .proximityalerttriggered import ProximityAlertTriggered
 from .games.callbackgame import CallbackGame
@@ -68,6 +71,7 @@
 from .passport.passportdata import PassportData
 from .inline.inlinekeyboardbutton import InlineKeyboardButton
 from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup
+from .messageautodeletetimerchanged import MessageAutoDeleteTimerChanged
 from .message import Message
 from .callbackquery import CallbackQuery
 from .choseninlineresult import ChosenInlineResult
@@ -157,8 +161,10 @@
     'CallbackQuery',
     'Chat',
     'ChatAction',
+    'ChatInviteLink',
     'ChatLocation',
     'ChatMember',
+    'ChatMemberUpdated',
     'ChatPermissions',
     'ChatPhoto',
     'ChosenInlineResult',
@@ -226,6 +232,7 @@
     'MAX_MESSAGE_LENGTH',
     'MaskPosition',
     'Message',
+    'MessageAutoDeleteTimerChanged',
     'MessageEntity',
     'MessageId',
     'OrderInfo',
@@ -272,5 +279,8 @@
     'Video',
     'VideoNote',
     'Voice',
+    'VoiceChatStarted',
+    'VoiceChatEnded',
+    'VoiceChatParticipantsInvited',
     'WebhookInfo',
 )
diff --git a/telegram/base.py b/telegram/base.py
index a3f9b0b46e9..030ea7b7809 100644
--- a/telegram/base.py
+++ b/telegram/base.py
@@ -46,15 +46,13 @@ def __getitem__(self, item: str) -> object:
 
     @staticmethod
     def parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]:
-        if not data:
-            return None
-        return data.copy()
+        return None if data is None else data.copy()
 
     @classmethod
     def de_json(cls: Type[TO], data: Optional[JSONDict], bot: 'Bot') -> Optional[TO]:
         data = cls.parse_data(data)
 
-        if not data:
+        if data is None:
             return None
 
         if cls == TelegramObject:
diff --git a/telegram/bot.py b/telegram/bot.py
index b76e1b1720a..6cc3ae511d5 100644
--- a/telegram/bot.py
+++ b/telegram/bot.py
@@ -85,6 +85,7 @@
     Voice,
     WebhookInfo,
     InlineKeyboardMarkup,
+    ChatInviteLink,
 )
 from telegram.constants import MAX_INLINE_QUERY_RESULTS
 from telegram.error import InvalidToken, TelegramError
@@ -2255,25 +2256,33 @@ def kick_chat_member(
         timeout: ODVInput[float] = DEFAULT_NONE,
         until_date: Union[int, datetime] = None,
         api_kwargs: JSONDict = None,
+        revoke_messages: bool = None,
     ) -> bool:
         """
-        Use this method to kick a user from a group or a supergroup or a channel. In the case of
+        Use this method to kick a user from a group, supergroup or a channel. In the case of
         supergroups and channels, the user will not be able to return to the group on their own
         using invite links, etc., unless unbanned first. The bot must be an administrator in the
-        group for this to work.
+        chat for this to work and must have the appropriate admin rights.
 
         Args:
-            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or  username
-                of the target channel (in the format @channelusername).
+            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username
+                of the target supergroup or channel (in the format @channelusername).
             user_id (:obj:`int`): Unique identifier of the target user.
             timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
                 the read timeout from the server (instead of the one specified during creation of
                 the connection pool).
             until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the user will
                 be unbanned, unix time. If user is banned for more than 366 days or less than 30
-                seconds from the current time they are considered to be banned forever.
+                seconds from the current time they are considered to be banned forever. Applied
+                for supergroups and channels only.
                 For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
                 bot will be used.
+            revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from
+                the chat for the user that is being removed. If :obj:`False`, the user will be able
+                to see messages in the group that were sent before the user was removed.
+                Always :obj:`True` for supergroups and channels.
+
+                .. versionadded:: 13.4
             api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
                 Telegram API.
 
@@ -2293,6 +2302,9 @@ def kick_chat_member(
                 )
             data['until_date'] = until_date
 
+        if revoke_messages is not None:
+            data['revoke_messages'] = revoke_messages
+
         result = self._post('kickChatMember', data, timeout=timeout, api_kwargs=api_kwargs)
 
         return result  # type: ignore[return-value]
@@ -2711,10 +2723,11 @@ def get_updates(
                 updates you want your bot to receive. For example, specify ["message",
                 "edited_channel_post", "callback_query"] to only receive updates of these types.
                 See :class:`telegram.Update` for a complete list of available update types.
-                Specify an empty list to receive all updates regardless of type (default). If not
-                specified, the previous setting will be used. Please note that this parameter
-                doesn't affect updates created before the call to the get_updates, so unwanted
-                updates may be received for a short period of time.
+                Specify an empty list to receive all updates except
+                :attr:`telegram.Update.chat_member` (default). If not specified, the previous
+                setting will be used. Please note that this parameter doesn't affect updates
+                created before the call to the get_updates, so unwanted updates may be received for
+                a short period of time.
             api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
                 Telegram API.
 
@@ -2799,10 +2812,11 @@ def set_webhook(
                 updates you want your bot to receive. For example, specify ["message",
                 "edited_channel_post", "callback_query"] to only receive updates of these types.
                 See :class:`telegram.Update` for a complete list of available update types.
-                Specify an empty list to receive all updates regardless of type (default). If not
-                specified, the previous setting will be used. Please note that this parameter
-                doesn't affect updates created before the call to the set_webhook, so unwanted
-                updates may be received for a short period of time.
+                Specify an empty list to receive all updates except
+                :attr:`telegram.Update.chat_member` (default). If not specified, the previous
+                setting will be used. Please note that this parameter doesn't affect updates
+                created before the call to the set_webhook, so unwanted updates may be received for
+                a short period of time.
             drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending
                 updates.
             timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
@@ -3588,6 +3602,8 @@ def promote_chat_member(
         timeout: ODVInput[float] = DEFAULT_NONE,
         api_kwargs: JSONDict = None,
         is_anonymous: bool = None,
+        can_manage_chat: bool = None,
+        can_manage_voice_chats: bool = None,
     ) -> bool:
         """
         Use this method to promote or demote a user in a supergroup or a channel. The bot must be
@@ -3596,16 +3612,28 @@ def promote_chat_member(
 
         Args:
             chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
-                of the target supergroup (in the format @supergroupusername).
+                of the target channel (in the format @channelusername).
             user_id (:obj:`int`): Unique identifier of the target user.
             is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence
                 in the chat is hidden.
+            can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
+                access the chat event log, chat statistics, message statistics in channels, see
+                channel members, see anonymous administrators in supergroups and ignore slow mode.
+                Implied by any other administrator privilege.
+
+                .. versionadded:: 13.4
+
+            can_manage_voice_chats (:obj:`bool`, optional): Pass :obj:`True`, if the administrator
+                can manage voice chats, supergroups only.
+
+                .. versionadded:: 13.4
+
             can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
                 change chat title, photo and other settings.
             can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
                 create channel posts, channels only.
             can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
-                edit messages of other users, channels only.
+                edit messages of other users and can pin messages, channels only.
             can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
                 delete messages of other users.
             can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can
@@ -3651,6 +3679,10 @@ def promote_chat_member(
             data['can_pin_messages'] = can_pin_messages
         if can_promote_members is not None:
             data['can_promote_members'] = can_promote_members
+        if can_manage_chat is not None:
+            data['can_manage_chat'] = can_manage_chat
+        if can_manage_voice_chats is not None:
+            data['can_manage_voice_chats'] = can_manage_voice_chats
 
         result = self._post('promoteChatMember', data, timeout=timeout, api_kwargs=api_kwargs)
 
@@ -3740,9 +3772,9 @@ def export_chat_invite_link(
         api_kwargs: JSONDict = None,
     ) -> str:
         """
-        Use this method to generate a new invite link for a chat; any previously generated link
-        is revoked. The bot must be an administrator in the chat for this to work and must have
-        the appropriate admin rights.
+        Use this method to generate a new primary invite link for a chat; any previously generated
+        link is revoked. The bot must be an administrator in the chat for this to work and must
+        have the appropriate admin rights.
 
         Args:
             chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
@@ -3753,6 +3785,13 @@ def export_chat_invite_link(
             api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
                 Telegram API.
 
+        Note:
+            Each administrator in a chat generates their own invite links. Bots can't use invite
+            links generated by other administrators. If you want your bot to work with invite
+            links, it will need to generate its own link using :meth:`export_chat_invite_link` or
+            by calling the :meth:`get_chat` method. If your bot needs to generate a new primary
+            invite link replacing its previous one, use :attr:`export_chat_invite_link` again.
+
         Returns:
             :obj:`str`: New invite link on success.
 
@@ -3766,6 +3805,155 @@ def export_chat_invite_link(
 
         return result  # type: ignore[return-value]
 
+    @log
+    def create_chat_invite_link(
+        self,
+        chat_id: Union[str, int],
+        expire_date: Union[int, datetime] = None,
+        member_limit: int = None,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> ChatInviteLink:
+        """
+        Use this method to create an additional invite link for a chat. The bot must be an
+        administrator in the chat for this to work and must have the appropriate admin rights.
+        The link can be revoked using the method :attr:`revokeChatInviteLink`.
+
+        Args:
+            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
+                of the target channel (in the format @channelusername).
+            expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
+                expire.
+                For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
+                bot will be used.
+            member_limit (:obj:`int`, optional): Maximum number of users that can be members of
+                the chat simultaneously after joining the chat via this invite link; 1-99999.
+            timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
+                the read timeout from the server (instead of the one specified during creation of
+                the connection pool).
+            api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
+                Telegram API.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :class:`telegram.ChatInviteLink`
+
+        Raises:
+            :class:`telegram.error.TelegramError`
+
+        """
+        data: JSONDict = {
+            'chat_id': chat_id,
+        }
+
+        if expire_date is not None:
+            if isinstance(expire_date, datetime):
+                expire_date = to_timestamp(
+                    expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None
+                )
+            data['expire_date'] = expire_date
+
+        if member_limit is not None:
+            data['member_limit'] = member_limit
+
+        result = self._post('createChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs)
+
+        return ChatInviteLink.de_json(result, self)  # type: ignore
+
+    @log
+    def edit_chat_invite_link(
+        self,
+        chat_id: Union[str, int],
+        invite_link: str,
+        expire_date: Union[int, datetime] = None,
+        member_limit: int = None,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> ChatInviteLink:
+        """
+        Use this method to edit a non-primary invite link created by the bot. The bot must be an
+        administrator in the chat for this to work and must have the appropriate admin rights.
+
+        Args:
+            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
+                of the target channel (in the format @channelusername).
+            invite_link (:obj:`str`): The invite link to edit.
+            expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will
+                expire.
+                For timezone naive :obj:`datetime.datetime` objects, the default timezone of the
+                bot will be used.
+            member_limit (:obj:`int`, optional): Maximum number of users that can be members of
+                the chat simultaneously after joining the chat via this invite link; 1-99999.
+            timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
+                the read timeout from the server (instead of the one specified during creation of
+                the connection pool).
+            api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
+                Telegram API.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :class:`telegram.ChatInviteLink`
+
+        Raises:
+            :class:`telegram.error.TelegramError`
+
+        """
+        data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link}
+
+        if expire_date is not None:
+            if isinstance(expire_date, datetime):
+                expire_date = to_timestamp(
+                    expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None
+                )
+            data['expire_date'] = expire_date
+
+        if member_limit is not None:
+            data['member_limit'] = member_limit
+
+        result = self._post('editChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs)
+
+        return ChatInviteLink.de_json(result, self)  # type: ignore
+
+    @log
+    def revoke_chat_invite_link(
+        self,
+        chat_id: Union[str, int],
+        invite_link: str,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> ChatInviteLink:
+        """
+        Use this method to revoke an invite link created by the bot. If the primary link is
+        revoked, a new link is automatically generated. The bot must be an administrator in the
+        chat for this to work and must have the appropriate admin rights.
+
+        Args:
+            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
+                of the target channel (in the format @channelusername).
+            invite_link (:obj:`str`): The invite link to edit.
+            timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
+                the read timeout from the server (instead of the one specified during creation of
+                the connection pool).
+            api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the
+                Telegram API.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :class:`telegram.ChatInviteLink`
+
+        Raises:
+            :class:`telegram.error.TelegramError`
+
+        """
+        data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link}
+
+        result = self._post('revokeChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs)
+
+        return ChatInviteLink.de_json(result, self)  # type: ignore
+
     @log
     def set_chat_photo(
         self,
@@ -4614,15 +4802,18 @@ def send_dice(
         allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE,
     ) -> Message:
         """
-        Use this method to send an animated emoji, which will have a random value. On success, the
-        sent Message is returned.
+        Use this method to send an animated emoji that will display a random value.
 
         Args:
-            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target private chat.
+            chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
+                of the target channel (in the format @channelusername).
             emoji (:obj:`str`, optional): Emoji on which the dice throw animation is based.
-                Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, or “🎰”. Dice can have values 1-6
-                for “🎲” and “🎯”, values 1-5 for “🏀” and “⚽”, and values 1-64 for “🎰”. Defaults
-                to “🎲”.
+                Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, "🎳", or “🎰”. Dice can have
+                values 1-6 for “🎲”, “🎯” and "🎳", values 1-5 for “🏀” and “⚽”, and values 1-64
+                for “🎰”. Defaults to “🎲”.
+
+                .. versionchanged:: 13.4
+                   Added the "🎳" emoji.
             disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
                 receive a notification with no sound.
             reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
@@ -4971,6 +5162,12 @@ def __hash__(self) -> int:
     """Alias for :attr:`set_chat_administrator_custom_title`"""
     exportChatInviteLink = export_chat_invite_link
     """Alias for :attr:`export_chat_invite_link`"""
+    createChatInviteLink = create_chat_invite_link
+    """Alias for :attr:`create_chat_invite_link`"""
+    editChatInviteLink = edit_chat_invite_link
+    """Alias for :attr:`edit_chat_invite_link`"""
+    revokeChatInviteLink = revoke_chat_invite_link
+    """Alias for :attr:`revoke_chat_invite_link`"""
     setChatPhoto = set_chat_photo
     """Alias for :attr:`set_chat_photo`"""
     deleteChatPhoto = delete_chat_photo
diff --git a/telegram/callbackquery.py b/telegram/callbackquery.py
index 3bafb8d31c9..00ba5cbf54d 100644
--- a/telegram/callbackquery.py
+++ b/telegram/callbackquery.py
@@ -47,7 +47,7 @@ class CallbackQuery(TelegramObject):
     considered equal, if their :attr:`id` is equal.
 
     Note:
-        * In Python `from` is a reserved word, use `from_user` instead.
+        * In Python ``from`` is a reserved word, use ``from_user`` instead.
         * Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present.
         * After the user presses an inline button, Telegram clients will display a progress bar
           until you call :attr:`answer`. It is, therefore, necessary to react
diff --git a/telegram/chat.py b/telegram/chat.py
index aa9cbc31d3e..afd44828d82 100644
--- a/telegram/chat.py
+++ b/telegram/chat.py
@@ -32,6 +32,7 @@
     from telegram import (
         Bot,
         ChatMember,
+        ChatInviteLink,
         Message,
         MessageId,
         ReplyMarkup,
@@ -91,6 +92,11 @@ class Chat(TelegramObject):
         slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between
             consecutive messages sent by each unprivileged user.
             Returned only in :meth:`telegram.Bot.get_chat`.
+        message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to
+            the chat will be automatically deleted; in seconds. Returned only in
+            :meth:`telegram.Bot.get_chat`.
+
+            .. versionadded:: 13.4
         bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
         sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set.
             Returned only in :meth:`telegram.Bot.get_chat`.
@@ -122,6 +128,11 @@ class Chat(TelegramObject):
         slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between
             consecutive messages sent by each unprivileged user. Returned only in
             :meth:`telegram.Bot.get_chat`.
+        message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to
+            the chat will be automatically deleted; in seconds. Returned only in
+            :meth:`telegram.Bot.get_chat`.
+
+            .. versionadded:: 13.4
         sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
         can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the
             sticker set.
@@ -162,6 +173,7 @@ def __init__(
         bio: str = None,
         linked_chat_id: int = None,
         location: ChatLocation = None,
+        message_auto_delete_time: int = None,
         **_kwargs: Any,
     ):
         # Required
@@ -181,6 +193,9 @@ def __init__(
         self.pinned_message = pinned_message
         self.permissions = permissions
         self.slow_mode_delay = slow_mode_delay
+        self.message_auto_delete_time = (
+            int(message_auto_delete_time) if message_auto_delete_time is not None else None
+        )
         self.sticker_set_name = sticker_set_name
         self.can_set_sticker_set = can_set_sticker_set
         self.linked_chat_id = linked_chat_id
@@ -216,7 +231,7 @@ def link(self) -> Optional[str]:
         return None
 
     @classmethod
-    def de_json(cls, data: JSONDict, bot: 'Bot') -> Optional['Chat']:
+    def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Chat']:
         data = cls.parse_data(data)
 
         if not data:
@@ -320,6 +335,7 @@ def kick_member(
         timeout: ODVInput[float] = DEFAULT_NONE,
         until_date: Union[int, datetime] = None,
         api_kwargs: JSONDict = None,
+        revoke_messages: bool = None,
     ) -> bool:
         """Shortcut for::
 
@@ -343,6 +359,7 @@ def kick_member(
             timeout=timeout,
             until_date=until_date,
             api_kwargs=api_kwargs,
+            revoke_messages=revoke_messages,
         )
 
     def unban_member(
@@ -384,6 +401,8 @@ def promote_member(
         timeout: ODVInput[float] = DEFAULT_NONE,
         api_kwargs: JSONDict = None,
         is_anonymous: bool = None,
+        can_manage_chat: bool = None,
+        can_manage_voice_chats: bool = None,
     ) -> bool:
         """Shortcut for::
 
@@ -412,6 +431,8 @@ def promote_member(
             timeout=timeout,
             api_kwargs=api_kwargs,
             is_anonymous=is_anonymous,
+            can_manage_chat=can_manage_chat,
+            can_manage_voice_chats=can_manage_voice_chats,
         )
 
     def restrict_member(
@@ -1391,3 +1412,106 @@ def copy_message(
             timeout=timeout,
             api_kwargs=api_kwargs,
         )
+
+    def export_invite_link(
+        self,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> str:
+        """Shortcut for::
+
+            bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
+
+        For the documentation of the arguments, please see
+        :meth:`telegram.Bot.export_chat_invite_link`.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :obj:`str`: New invite link on success.
+
+        """
+        return self.bot.export_chat_invite_link(
+            chat_id=self.id, timeout=timeout, api_kwargs=api_kwargs
+        )
+
+    def create_invite_link(
+        self,
+        expire_date: Union[int, datetime] = None,
+        member_limit: int = None,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> 'ChatInviteLink':
+        """Shortcut for::
+
+            bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
+
+        For the documentation of the arguments, please see
+        :meth:`telegram.Bot.create_chat_invite_link`.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :class:`telegram.ChatInviteLink`
+
+        """
+        return self.bot.create_chat_invite_link(
+            chat_id=self.id,
+            expire_date=expire_date,
+            member_limit=member_limit,
+            timeout=timeout,
+            api_kwargs=api_kwargs,
+        )
+
+    def edit_invite_link(
+        self,
+        invite_link: str,
+        expire_date: Union[int, datetime] = None,
+        member_limit: int = None,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> 'ChatInviteLink':
+        """Shortcut for::
+
+            bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
+
+        For the documentation of the arguments, please see
+        :meth:`telegram.Bot.edit_chat_invite_link`.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :class:`telegram.ChatInviteLink`
+
+        """
+        return self.bot.edit_chat_invite_link(
+            chat_id=self.id,
+            invite_link=invite_link,
+            expire_date=expire_date,
+            member_limit=member_limit,
+            timeout=timeout,
+            api_kwargs=api_kwargs,
+        )
+
+    def revoke_invite_link(
+        self,
+        invite_link: str,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> 'ChatInviteLink':
+        """Shortcut for::
+
+            bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs)
+
+        For the documentation of the arguments, please see
+        :meth:`telegram.Bot.revoke_chat_invite_link`.
+
+        .. versionadded:: 13.4
+
+        Returns:
+            :class:`telegram.ChatInviteLink`
+
+        """
+        return self.bot.revoke_chat_invite_link(
+            chat_id=self.id, invite_link=invite_link, timeout=timeout, api_kwargs=api_kwargs
+        )
diff --git a/telegram/chatinvitelink.py b/telegram/chatinvitelink.py
new file mode 100644
index 00000000000..075d514af6c
--- /dev/null
+++ b/telegram/chatinvitelink.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+"""This module contains an object that represents an invite link for a chat."""
+import datetime
+from typing import TYPE_CHECKING, Any, Optional
+
+from telegram import TelegramObject, User
+from telegram.utils.helpers import from_timestamp, to_timestamp
+from telegram.utils.types import JSONDict
+
+if TYPE_CHECKING:
+    from telegram import Bot
+
+
+class ChatInviteLink(TelegramObject):
+    """This object represents an invite link for a chat.
+
+    Objects of this class are comparable in terms of equality. Two objects of this class are
+    considered equal, if their :attr:`invite_link` and :attr:`creator` are equal.
+
+    Args:
+        invite_link (:obj:`str`): The invite link.
+        creator (:class:`telegram.User`): Creator of the link.
+        is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
+        is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
+        expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or
+            has been expired.
+        member_limit (:obj:`int`, optional): Maximum number of users that can be members of the
+            chat simultaneously after joining the chat via this invite link; 1-99999.
+
+    Attributes:
+        invite_link (:obj:`str`): The invite link. If the link was created by another chat
+            administrator, then the second part of the link will be replaced with ``'…'``.
+        creator (:class:`telegram.User`): Creator of the link.
+        is_primary (:obj:`bool`): :obj:`True`, if the link is primary.
+        is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked.
+        expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or
+            has been expired.
+        member_limit (:obj:`int`): Optional. Maximum number of users that can be members
+            of the chat simultaneously after joining the chat via this invite link; 1-99999.
+
+    .. versionadded:: 13.4
+
+    """
+
+    def __init__(
+        self,
+        invite_link: str,
+        creator: User,
+        is_primary: bool,
+        is_revoked: bool,
+        expire_date: datetime.datetime = None,
+        member_limit: int = None,
+        **_kwargs: Any,
+    ):
+        # Required
+        self.invite_link = invite_link
+        self.creator = creator
+        self.is_primary = is_primary
+        self.is_revoked = is_revoked
+
+        # Optionals
+        self.expire_date = expire_date
+        self.member_limit = int(member_limit) if member_limit is not None else None
+
+        self._id_attrs = (self.invite_link, self.creator, self.is_primary, self.is_revoked)
+
+    @classmethod
+    def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatInviteLink']:
+        data = cls.parse_data(data)
+
+        if not data:
+            return None
+
+        data['creator'] = User.de_json(data.get('creator'), bot)
+        data['until_date'] = from_timestamp(data.get('expire_date', None))
+
+        return cls(**data)
+
+    def to_dict(self) -> JSONDict:
+        data = super().to_dict()
+
+        data['expire_date'] = to_timestamp(self.expire_date)
+
+        return data
diff --git a/telegram/chatmember.py b/telegram/chatmember.py
index 8d449ef7ab8..68141cd3d93 100644
--- a/telegram/chatmember.py
+++ b/telegram/chatmember.py
@@ -46,6 +46,18 @@ class ChatMember(TelegramObject):
             restrictions will be lifted for this user.
         can_be_edited (:obj:`bool`, optional): Administrators only. :obj:`True`, if the bot is
             allowed to edit administrator privileges of that user.
+        can_manage_chat (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
+            administrator can access the chat event log, chat statistics, message statistics in
+            channels, see channel members, see anonymous administrators in supergroups and ignore
+            slow mode. Implied by any other administrator privilege.
+
+            .. versionadded:: 13.4
+
+        can_manage_voice_chats (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
+            administrator can manage voice chats.
+
+            .. versionadded:: 13.4
+
         can_change_info (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`,
             if the user can change the chat title, photo and other settings.
         can_post_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the
@@ -87,6 +99,17 @@ class ChatMember(TelegramObject):
             for this user.
         can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator
             privileges of that user.
+        can_manage_chat (:obj:`bool`): Optional. If the administrator can access the chat event
+            log, chat statistics, message statistics in channels, see channel members, see
+            anonymous administrators in supergroups and ignore slow mode.
+
+            .. versionadded:: 13.4
+
+        can_manage_voice_chats (:obj:`bool`): Optional. if the administrator can manage
+            voice chats.
+
+            .. versionadded:: 13.4
+
         can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and
             other settings.
         can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel.
@@ -150,6 +173,8 @@ def __init__(
         is_member: bool = None,
         custom_title: str = None,
         is_anonymous: bool = None,
+        can_manage_chat: bool = None,
+        can_manage_voice_chats: bool = None,
         **_kwargs: Any,
     ):
         # Required
@@ -175,6 +200,8 @@ def __init__(
         self.can_send_other_messages = can_send_other_messages
         self.can_add_web_page_previews = can_add_web_page_previews
         self.is_member = is_member
+        self.can_manage_chat = can_manage_chat
+        self.can_manage_voice_chats = can_manage_voice_chats
 
         self._id_attrs = (self.user, self.status)
 
diff --git a/telegram/chatmemberupdated.py b/telegram/chatmemberupdated.py
new file mode 100644
index 00000000000..25dc215e369
--- /dev/null
+++ b/telegram/chatmemberupdated.py
@@ -0,0 +1,115 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+"""This module contains an object that represents a Telegram ChatMemberUpdated."""
+import datetime
+from typing import TYPE_CHECKING, Any, Optional
+
+from telegram import TelegramObject, User, Chat, ChatMember, ChatInviteLink
+from telegram.utils.helpers import from_timestamp, to_timestamp
+from telegram.utils.types import JSONDict
+
+if TYPE_CHECKING:
+    from telegram import Bot
+
+
+class ChatMemberUpdated(TelegramObject):
+    """This object represents changes in the status of a chat member.
+
+    Objects of this class are comparable in terms of equality. Two objects of this class are
+    considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`,
+    :attr:`old_chat_member` and :attr:`new_chat_member` are equal.
+
+    .. versionadded:: 13.4
+
+    Note:
+        In Python ``from`` is a reserved word, use ``from_user`` instead.
+
+    Args:
+        chat (:class:`telegram.Chat`): Chat the user belongs to.
+        from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
+        date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
+            :class:`datetime.datetime`.
+        old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
+        new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
+        invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used
+            by the user to join the chat. For joining by invite link events only.
+
+    Attributes:
+        chat (:class:`telegram.Chat`): Chat the user belongs to.
+        from_user (:class:`telegram.User`): Performer of the action, which resulted in the change.
+        date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to
+            :class:`datetime.datetime`.
+        old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member.
+        new_chat_member (:class:`telegram.ChatMember`): New information about the chat member.
+        invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used
+            by the user to join the chat.
+
+    """
+
+    def __init__(
+        self,
+        chat: Chat,
+        from_user: User,
+        date: datetime.datetime,
+        old_chat_member: ChatMember,
+        new_chat_member: ChatMember,
+        invite_link: ChatInviteLink = None,
+        **_kwargs: Any,
+    ):
+        # Required
+        self.chat = chat
+        self.from_user = from_user
+        self.date = date
+        self.old_chat_member = old_chat_member
+        self.new_chat_member = new_chat_member
+
+        # Optionals
+        self.invite_link = invite_link
+
+        self._id_attrs = (
+            self.chat,
+            self.from_user,
+            self.date,
+            self.old_chat_member,
+            self.new_chat_member,
+        )
+
+    @classmethod
+    def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMemberUpdated']:
+        data = cls.parse_data(data)
+
+        if not data:
+            return None
+
+        data['chat'] = Chat.de_json(data.get('chat'), bot)
+        data['from_user'] = User.de_json(data.get('from'), bot)
+        data['date'] = from_timestamp(data.get('date'))
+        data['old_chat_member'] = ChatMember.de_json(data.get('old_chat_member'), bot)
+        data['new_chat_member'] = ChatMember.de_json(data.get('new_chat_member'), bot)
+        data['invite_link'] = ChatInviteLink.de_json(data.get('invite_link'), bot)
+
+        return cls(**data)
+
+    def to_dict(self) -> JSONDict:
+        data = super().to_dict()
+
+        # Required
+        data['date'] = to_timestamp(self.date)
+
+        return data
diff --git a/telegram/choseninlineresult.py b/telegram/choseninlineresult.py
index 8b266da6bf2..24416728ee6 100644
--- a/telegram/choseninlineresult.py
+++ b/telegram/choseninlineresult.py
@@ -37,7 +37,7 @@ class ChosenInlineResult(TelegramObject):
     considered equal, if their :attr:`result_id` is equal.
 
     Note:
-        * In Python `from` is a reserved word, use `from_user` instead.
+        * In Python ``from`` is a reserved word, use ``from_user`` instead.
         * It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in
           order to receive these objects in updates.
 
diff --git a/telegram/constants.py b/telegram/constants.py
index ceb574d9ca4..b5ce88bca45 100644
--- a/telegram/constants.py
+++ b/telegram/constants.py
@@ -182,12 +182,14 @@
 DICE_BASKETBALL: str = '🏀'
 DICE_FOOTBALL: str = '⚽'
 DICE_SLOT_MACHINE: str = '🎰'
+DICE_BOWLING: str = '🎳'
 DICE_ALL_EMOJI: List[str] = [
     DICE_DICE,
     DICE_DARTS,
     DICE_BASKETBALL,
     DICE_FOOTBALL,
     DICE_SLOT_MACHINE,
+    DICE_BOWLING,
 ]
 
 MESSAGEENTITY_MENTION: str = 'mention'
diff --git a/telegram/dice.py b/telegram/dice.py
index 1b1300af3ba..856e5d8f8ce 100644
--- a/telegram/dice.py
+++ b/telegram/dice.py
@@ -45,13 +45,17 @@ class Dice(TelegramObject):
         3 indicates that the goal was missed. However, this behaviour is undocumented and might
         be changed by Telegram.
 
+        If :attr:`emoji` is "🎳", a value of 6 knocks all the pins, while a value of 1 means all
+        the pins were missed. However, this behaviour is undocumented and might be changed by
+        Telegram.
+
         If :attr:`emoji` is "🎰", each value corresponds to a unique combination of symbols, which
         can be found at our `wiki <https://git.io/JkeC6>`_. However, this behaviour is undocumented
         and might be changed by Telegram.
 
     Args:
-        value (:obj:`int`): Value of the dice. 1-6 for dice and darts, 1-5 for basketball and
-            football/soccer ball, 1-64 for slot machine.
+        value (:obj:`int`): Value of the dice. 1-6 for dice, darts and bowling balls, 1-5 for
+            basketball and football/soccer ball, 1-64 for slot machine.
         emoji (:obj:`str`): Emoji on which the dice throw animation is based.
 
     Attributes:
@@ -76,5 +80,7 @@ def __init__(self, value: int, emoji: str, **_kwargs: Any):
     """:const:`telegram.constants.DICE_FOOTBALL`"""
     SLOT_MACHINE: ClassVar[str] = constants.DICE_SLOT_MACHINE
     """:const:`telegram.constants.DICE_SLOT_MACHINE`"""
+    BOWLING: ClassVar[str] = constants.DICE_BOWLING
+    """:const:`telegram.constants.DICE_BOWLING`"""
     ALL_EMOJI: ClassVar[List[str]] = constants.DICE_ALL_EMOJI
     """:const:`telegram.constants.DICE_ALL_EMOJI`"""
diff --git a/telegram/ext/__init__.py b/telegram/ext/__init__.py
index 380a0e41844..f536c2be200 100644
--- a/telegram/ext/__init__.py
+++ b/telegram/ext/__init__.py
@@ -43,6 +43,7 @@
 from .messagequeue import DelayQueue
 from .pollanswerhandler import PollAnswerHandler
 from .pollhandler import PollHandler
+from .chatmemberhandler import ChatMemberHandler
 from .defaults import Defaults
 
 __all__ = (
@@ -78,5 +79,6 @@
     'PrefixHandler',
     'PollAnswerHandler',
     'PollHandler',
+    'ChatMemberHandler',
     'Defaults',
 )
diff --git a/telegram/ext/chatmemberhandler.py b/telegram/ext/chatmemberhandler.py
new file mode 100644
index 00000000000..35ce49e2a4d
--- /dev/null
+++ b/telegram/ext/chatmemberhandler.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2019-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+"""This module contains the ChatMemberHandler classes."""
+from typing import ClassVar, TypeVar, Union, Callable, TYPE_CHECKING
+
+from telegram import Update
+from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE
+from .handler import Handler
+
+if TYPE_CHECKING:
+    from telegram.ext import CallbackContext
+
+RT = TypeVar('RT')
+
+
+class ChatMemberHandler(Handler[Update]):
+    """Handler class to handle Telegram updates that contain a chat member update.
+
+    .. versionadded:: 13.4
+
+    Note:
+        :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you
+        can use to keep any data in will be sent to the :attr:`callback` function. Related to
+        either the user or the chat that the update was sent in. For each update from the same user
+        or in the same chat, it will be the same ``dict``.
+
+        Note that this is DEPRECATED, and you should use context based callbacks. See
+        https://git.io/fxJuV for more info.
+
+    Warning:
+        When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom
+        attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info.
+
+    Args:
+        callback (:obj:`callable`): The callback function for this handler. Will be called when
+            :attr:`check_update` has determined that an update should be processed by this handler.
+            Callback signature for context based API:
+
+            ``def callback(update: Update, context: CallbackContext)``
+
+            The return value of the callback is usually ignored except for the special case of
+            :class:`telegram.ext.ConversationHandler`.
+        chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`,
+            :attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle
+            only updates with :attr:`telegram.Update.my_chat_member`,
+            :attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`.
+        pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
+            ``update_queue`` will be passed to the callback function. It will be the ``Queue``
+            instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
+            that contains new updates which can be used to insert updates. Default is :obj:`False`.
+            DEPRECATED: Please switch to context based callbacks.
+        pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
+            ``job_queue`` will be passed to the callback function. It will be a
+            :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
+            which can be used to schedule new jobs. Default is :obj:`False`.
+            DEPRECATED: Please switch to context based callbacks.
+        pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
+            ``user_data`` will be passed to the callback function. Default is :obj:`False`.
+            DEPRECATED: Please switch to context based callbacks.
+        pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called
+            ``chat_data`` will be passed to the callback function. Default is :obj:`False`.
+            DEPRECATED: Please switch to context based callbacks.
+        run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
+            Defaults to :obj:`False`.
+
+    Attributes:
+        callback (:obj:`callable`): The callback function for this handler.
+        chat_member_types (:obj:`int`, optional): Specifies if this handler should handle
+            only updates with :attr:`telegram.Update.my_chat_member`,
+            :attr:`telegram.Update.chat_member` or both.
+        pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be
+            passed to the callback function.
+        pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to
+            the callback function.
+        pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to
+            the callback function.
+        pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to
+            the callback function.
+        run_async (:obj:`bool`): Determines whether the callback will run asynchronously.
+
+    """
+
+    MY_CHAT_MEMBER: ClassVar[int] = -1
+    """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`."""
+    CHAT_MEMBER: ClassVar[int] = 0
+    """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`."""
+    ANY_CHAT_MEMBER: ClassVar[int] = 1
+    """:obj:`int`: Used as a constant to handle bot :attr:`telegram.Update.my_chat_member`
+    and :attr:`telegram.Update.chat_member`."""
+
+    def __init__(
+        self,
+        callback: Callable[[Update, 'CallbackContext'], RT],
+        chat_member_types: int = MY_CHAT_MEMBER,
+        pass_update_queue: bool = False,
+        pass_job_queue: bool = False,
+        pass_user_data: bool = False,
+        pass_chat_data: bool = False,
+        run_async: Union[bool, DefaultValue] = DEFAULT_FALSE,
+    ):
+        super().__init__(
+            callback,
+            pass_update_queue=pass_update_queue,
+            pass_job_queue=pass_job_queue,
+            pass_user_data=pass_user_data,
+            pass_chat_data=pass_chat_data,
+            run_async=run_async,
+        )
+
+        self.chat_member_types = chat_member_types
+
+    def check_update(self, update: object) -> bool:
+        """Determines whether an update should be passed to this handlers :attr:`callback`.
+
+        Args:
+            update (:class:`telegram.Update` | :obj:`object`): Incoming update.
+
+        Returns:
+            :obj:`bool`
+
+        """
+        if isinstance(update, Update):
+            if not (update.my_chat_member or update.chat_member):
+                return False
+            if self.chat_member_types == self.ANY_CHAT_MEMBER:
+                return True
+            if self.chat_member_types == self.CHAT_MEMBER:
+                return bool(update.chat_member)
+            return bool(update.my_chat_member)
+        return False
diff --git a/telegram/ext/filters.py b/telegram/ext/filters.py
index eaf1f100e1a..a351cb234a2 100644
--- a/telegram/ext/filters.py
+++ b/telegram/ext/filters.py
@@ -1005,6 +1005,15 @@ def filter(self, message: Message) -> bool:
             :attr: `telegram.Message.supergroup_chat_created` or
             :attr: `telegram.Message.channel_chat_created`."""
 
+        class _MessageAutoDeleteTimerChanged(MessageFilter):
+            name = 'MessageAutoDeleteTimerChanged'
+
+            def filter(self, message: Message) -> bool:
+                return bool(message.message_auto_delete_timer_changed)
+
+        message_auto_delete_timer_changed = _MessageAutoDeleteTimerChanged()
+        """Messages that contain :attr:`message_auto_delete_timer_changed`"""
+
         class _Migrate(MessageFilter):
             name = 'Filters.status_update.migrate'
 
@@ -1042,6 +1051,33 @@ def filter(self, message: Message) -> bool:
         proximity_alert_triggered = _ProximityAlertTriggered()
         """Messages that contain :attr:`telegram.Message.proximity_alert_triggered`."""
 
+        class _VoiceChatStarted(MessageFilter):
+            name = 'Filters.status_update.voice_chat_started'
+
+            def filter(self, message: Message) -> bool:
+                return bool(message.voice_chat_started)
+
+        voice_chat_started = _VoiceChatStarted()
+        """Messages that contain :attr:`telegram.Message.voice_chat_started`."""
+
+        class _VoiceChatEnded(MessageFilter):
+            name = 'Filters.status_update.voice_chat_ended'
+
+            def filter(self, message: Message) -> bool:
+                return bool(message.voice_chat_ended)
+
+        voice_chat_ended = _VoiceChatEnded()
+        """Messages that contain :attr:`telegram.Message.voice_chat_ended`."""
+
+        class _VoiceChatParticipantsInvited(MessageFilter):
+            name = 'Filters.status_update.voice_chat_participants_invited'
+
+            def filter(self, message: Message) -> bool:
+                return bool(message.voice_chat_participants_invited)
+
+        voice_chat_participants_invited = _VoiceChatParticipantsInvited()
+        """Messages that contain :attr:`telegram.Message.voice_chat_participants_invited`."""
+
         name = 'Filters.status_update'
 
         def filter(self, message: Update) -> bool:
@@ -1052,10 +1088,14 @@ def filter(self, message: Update) -> bool:
                 or self.new_chat_photo(message)
                 or self.delete_chat_photo(message)
                 or self.chat_created(message)
+                or self.message_auto_delete_timer_changed(message)
                 or self.migrate(message)
                 or self.pinned_message(message)
                 or self.connected_website(message)
                 or self.proximity_alert_triggered(message)
+                or self.voice_chat_started(message)
+                or self.voice_chat_ended(message)
+                or self.voice_chat_participants_invited(message)
             )
 
     status_update = _StatusUpdate()
@@ -1085,10 +1125,27 @@ def filter(self, message: Update) -> bool:
             :attr:`telegram.Message.new_chat_photo`.
         new_chat_title: Messages that contain
             :attr:`telegram.Message.new_chat_title`.
+        message_auto_delete_timer_changed: Messages that contain
+            :attr:`message_auto_delete_timer_changed`.
+
+            .. versionadded:: 13.4
         pinned_message: Messages that contain
             :attr:`telegram.Message.pinned_message`.
         proximity_alert_triggered: Messages that contain
             :attr:`telegram.Message.proximity_alert_triggered`.
+        voice_chat_started: Messages that contain
+            :attr:`telegram.Message.voice_chat_started`.
+
+            .. versionadded:: 13.4
+        voice_chat_ended: Messages that contain
+            :attr:`telegram.Message.voice_chat_ended`.
+
+            .. versionadded:: 13.4
+        voice_chat_participants_invited: Messages that contain
+            :attr:`telegram.Message.voice_chat_participants_invited`.
+
+            .. versionadded:: 13.4
+
     """
 
     class _Forwarded(MessageFilter):
@@ -1831,6 +1888,7 @@ class _Dice(_DiceEmoji):
         basketball = _DiceEmoji('🏀', 'basketball')
         football = _DiceEmoji('⚽')
         slot_machine = _DiceEmoji('🎰')
+        bowling = _DiceEmoji('🎳', 'bowling')
 
     dice = _Dice()
     """Dice Messages. If an integer or a list of integers is passed, it filters messages to only
@@ -1863,6 +1921,11 @@ class _Dice(_DiceEmoji):
             as for :attr:`Filters.dice`.
         slot_machine: Dice messages with the emoji 🎰. Passing a list of integers is supported just
             as for :attr:`Filters.dice`.
+        bowling: Dice messages with the emoji 🎳. Passing a list of integers is supported just
+            as for :attr:`Filters.dice`.
+
+            .. versionadded:: 13.4
+
     """
 
     class language(MessageFilter):
diff --git a/telegram/inline/inlinequery.py b/telegram/inline/inlinequery.py
index 84129949f6e..58e503d00ec 100644
--- a/telegram/inline/inlinequery.py
+++ b/telegram/inline/inlinequery.py
@@ -38,7 +38,7 @@ class InlineQuery(TelegramObject):
     considered equal, if their :attr:`id` is equal.
 
     Note:
-        * In Python `from` is a reserved word, use `from_user` instead.
+        * In Python ``from`` is a reserved word, use ``from_user`` instead.
 
     Args:
         id (:obj:`str`): Unique identifier for this query.
diff --git a/telegram/inline/inlinequeryresult.py b/telegram/inline/inlinequeryresult.py
index 0280f6c9ea9..cb7c38acc71 100644
--- a/telegram/inline/inlinequeryresult.py
+++ b/telegram/inline/inlinequeryresult.py
@@ -31,6 +31,10 @@ class InlineQueryResult(TelegramObject):
     Objects of this class are comparable in terms of equality. Two objects of this class are
     considered equal, if their :attr:`id` is equal.
 
+    Note:
+        All URLs passed in inline query results will be available to end users and therefore must
+        be assumed to be public.
+
     Args:
         type (:obj:`str`): Type of the result.
         id (:obj:`str`): Unique identifier for this result, 1-64 Bytes.
diff --git a/telegram/message.py b/telegram/message.py
index 92fc529a15a..61fdc7e6aed 100644
--- a/telegram/message.py
+++ b/telegram/message.py
@@ -47,8 +47,12 @@
     Video,
     VideoNote,
     Voice,
+    VoiceChatStarted,
+    VoiceChatEnded,
+    VoiceChatParticipantsInvited,
     ProximityAlertTriggered,
     ReplyMarkup,
+    MessageAutoDeleteTimerChanged,
 )
 from telegram.utils.helpers import (
     escape_markdown,
@@ -83,7 +87,7 @@ class Message(TelegramObject):
     considered equal, if their :attr:`message_id` and :attr:`chat` are equal.
 
     Note:
-        In Python `from` is a reserved word, use `from_user` instead.
+        In Python ``from`` is a reserved word, use ``from_user`` instead.
 
     Args:
         message_id (:obj:`int`): Unique message identifier inside this chat.
@@ -165,6 +169,10 @@ class Message(TelegramObject):
             created. This field can't be received in a message coming through updates, because bot
             can't be a member of a channel when it is created. It can only be found in
             :attr:`reply_to_message` if someone replies to a very first message in a channel.
+        message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \
+            optional): Service message: auto-delete timer settings changed in the chat.
+
+            .. versionadded:: 13.4
         migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup with
             the specified identifier. This number may be greater than 32 bits and some programming
             languages may have difficulty/silent defects in interpreting it. But it is smaller than
@@ -196,6 +204,18 @@ class Message(TelegramObject):
         proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service
             message. A user in the chat triggered another user's proximity alert while sharing
             Live Location.
+        voice_chat_started (:class:`telegram.VoiceChatStarted`, optional): Service message about
+            a voice chat started in the chat.
+
+            .. versionadded:: 13.4
+        voice_chat_ended (:class:`telegram.VoiceChatEnded`, optional): Service message about a
+            voice chat ended in the chat.
+
+            .. versionadded:: 13.4
+        voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited` optional):
+            Service message about new members invited to a voice chat.
+
+            .. versionadded:: 13.4
         reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
             to the message. ``login_url`` buttons are represented as ordinary url buttons.
         bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
@@ -257,6 +277,10 @@ class Message(TelegramObject):
         group_chat_created (:obj:`bool`): Optional. The group has been created.
         supergroup_chat_created (:obj:`bool`): Optional. The supergroup has been created.
         channel_chat_created (:obj:`bool`): Optional. The channel has been created.
+        message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`):
+            Optional. Service message: auto-delete timer settings changed in the chat.
+
+            .. versionadded:: 13.4
         migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup with
             the specified identifier.
         migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group
@@ -281,6 +305,18 @@ class Message(TelegramObject):
         proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service
             message. A user in the chat triggered another user's proximity alert while sharing
             Live Location.
+        voice_chat_started (:class:`telegram.VoiceChatStarted`): Optional. Represents a service
+            message about voice chat started in the chat.
+
+            .. versionadded:: 13.4
+        voice_chat_ended (:class:`telegram.VoiceChatEnded`): Optional. Represents a service
+            message about a voice chat ended in the chat.
+
+            .. versionadded:: 13.4
+        voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited`): Optional.
+            Represents a service message about new members invited to a voice chat.
+
+            .. versionadded:: 13.4
         reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
             to the message.
         bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
@@ -316,6 +352,7 @@ class Message(TelegramObject):
         'group_chat_created',
         'supergroup_chat_created',
         'channel_chat_created',
+        'message_auto_delete_timer_changed',
         'migrate_to_chat_id',
         'migrate_from_chat_id',
         'pinned_message',
@@ -323,6 +360,9 @@ class Message(TelegramObject):
         'dice',
         'passport_data',
         'proximity_alert_triggered',
+        'voice_chat_started',
+        'voice_chat_ended',
+        'voice_chat_participants_invited',
     ] + ATTACHMENT_TYPES
 
     def __init__(
@@ -379,6 +419,10 @@ def __init__(
         via_bot: User = None,
         proximity_alert_triggered: ProximityAlertTriggered = None,
         sender_chat: Chat = None,
+        voice_chat_started: VoiceChatStarted = None,
+        voice_chat_ended: VoiceChatEnded = None,
+        voice_chat_participants_invited: VoiceChatParticipantsInvited = None,
+        message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = None,
         **_kwargs: Any,
     ):
         # Required
@@ -418,6 +462,7 @@ def __init__(
         self.migrate_to_chat_id = migrate_to_chat_id
         self.migrate_from_chat_id = migrate_from_chat_id
         self.channel_chat_created = bool(channel_chat_created)
+        self.message_auto_delete_timer_changed = message_auto_delete_timer_changed
         self.pinned_message = pinned_message
         self.forward_from_message_id = forward_from_message_id
         self.invoice = invoice
@@ -433,6 +478,9 @@ def __init__(
         self.dice = dice
         self.via_bot = via_bot
         self.proximity_alert_triggered = proximity_alert_triggered
+        self.voice_chat_started = voice_chat_started
+        self.voice_chat_ended = voice_chat_ended
+        self.voice_chat_participants_invited = voice_chat_participants_invited
         self.reply_markup = reply_markup
         self.bot = bot
 
@@ -489,6 +537,9 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Message']:
         data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot)
         data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot)
         data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot)
+        data['message_auto_delete_timer_changed'] = MessageAutoDeleteTimerChanged.de_json(
+            data.get('message_auto_delete_timer_changed'), bot
+        )
         data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot)
         data['invoice'] = Invoice.de_json(data.get('invoice'), bot)
         data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot)
@@ -500,7 +551,11 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Message']:
             data.get('proximity_alert_triggered'), bot
         )
         data['reply_markup'] = InlineKeyboardMarkup.de_json(data.get('reply_markup'), bot)
-
+        data['voice_chat_started'] = VoiceChatStarted.de_json(data.get('voice_chat_started'), bot)
+        data['voice_chat_ended'] = VoiceChatEnded.de_json(data.get('voice_chat_ended'), bot)
+        data['voice_chat_participants_invited'] = VoiceChatParticipantsInvited.de_json(
+            data.get('voice_chat_participants_invited'), bot
+        )
         return cls(bot=bot, **data)
 
     @property
diff --git a/telegram/messageautodeletetimerchanged.py b/telegram/messageautodeletetimerchanged.py
new file mode 100644
index 00000000000..842bd162a70
--- /dev/null
+++ b/telegram/messageautodeletetimerchanged.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+"""This module contains an object that represents a change in the Telegram message auto
+deletion."""
+
+from typing import Any
+
+from telegram import TelegramObject
+
+
+class MessageAutoDeleteTimerChanged(TelegramObject):
+    """This object represents a service message about a change in auto-delete timer settings.
+
+    Objects of this class are comparable in terms of equality. Two objects of this class are
+    considered equal, if their :attr:`message_auto_delete_time` is equal.
+
+    .. versionadded:: 13.4
+
+    Args:
+        message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the
+            chat.
+        **kwargs (:obj:`dict`): Arbitrary keyword arguments.
+
+    Attributes:
+        message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the
+            chat.
+
+    """
+
+    def __init__(
+        self,
+        message_auto_delete_time: int,
+        **_kwargs: Any,
+    ):
+        self.message_auto_delete_time = int(message_auto_delete_time)
+
+        self._id_attrs = (self.message_auto_delete_time,)
diff --git a/telegram/payment/precheckoutquery.py b/telegram/payment/precheckoutquery.py
index 60ea90ca0c0..264a822dcd1 100644
--- a/telegram/payment/precheckoutquery.py
+++ b/telegram/payment/precheckoutquery.py
@@ -35,7 +35,7 @@ class PreCheckoutQuery(TelegramObject):
     considered equal, if their :attr:`id` is equal.
 
     Note:
-        In Python `from` is a reserved word, use `from_user` instead.
+        In Python ``from`` is a reserved word, use ``from_user`` instead.
 
     Args:
         id (:obj:`str`): Unique query identifier.
diff --git a/telegram/payment/shippingquery.py b/telegram/payment/shippingquery.py
index df57a6b7ac9..f9b37230299 100644
--- a/telegram/payment/shippingquery.py
+++ b/telegram/payment/shippingquery.py
@@ -35,7 +35,7 @@ class ShippingQuery(TelegramObject):
     considered equal, if their :attr:`id` is equal.
 
     Note:
-        In Python `from` is a reserved word, use `from_user` instead.
+        In Python ``from`` is a reserved word, use ``from_user`` instead.
 
     Args:
         id (:obj:`str`): Unique query identifier.
diff --git a/telegram/update.py b/telegram/update.py
index bb7cd8f2fd5..06a5de019bc 100644
--- a/telegram/update.py
+++ b/telegram/update.py
@@ -29,6 +29,7 @@
     PreCheckoutQuery,
     ShippingQuery,
     TelegramObject,
+    ChatMemberUpdated,
 )
 from telegram.poll import PollAnswer
 from telegram.utils.types import JSONDict
@@ -74,6 +75,19 @@ class Update(TelegramObject):
         poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer
             in a non-anonymous poll. Bots receive new votes only in polls that were sent
             by the bot itself.
+        my_chat_member (:class:`telegram.ChatMemberUpdated`, optional): The bot's chat member
+            status was updated in a chat. For private chats, this update is received only when the
+            bot is blocked or unblocked by the user.
+
+            .. versionadded:: 13.4
+        chat_member (:class:`telegram.ChatMemberUpdated`, optional): A chat member's status was
+            updated in a chat. The bot must be an administrator in the chat and must explicitly
+            specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these
+            updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
+            :meth:`telegram.ext.Updater.start_polling` and
+            :meth:`telegram.ext.Updater.start_webhook`).
+
+            .. versionadded:: 13.4
         **kwargs (:obj:`dict`): Arbitrary keyword arguments.
 
     Attributes:
@@ -94,6 +108,19 @@ class Update(TelegramObject):
         poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer
             in a non-anonymous poll. Bots receive new votes only in polls that were sent
             by the bot itself.
+        my_chat_member (:class:`telegram.ChatMemberUpdated`): Optional. The bot's chat member
+            status was updated in a chat. For private chats, this update is received only when the
+            bot is blocked or unblocked by the user.
+
+            .. versionadded:: 13.4
+        chat_member (:class:`telegram.ChatMemberUpdated`): Optional. A chat member's status was
+            updated in a chat. The bot must be an administrator in the chat and must explicitly
+            specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these
+            updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`,
+            :meth:`telegram.ext.Updater.start_polling` and
+            :meth:`telegram.ext.Updater.start_webhook`).
+
+            .. versionadded:: 13.4
 
     """
 
@@ -111,6 +138,8 @@ def __init__(
         pre_checkout_query: PreCheckoutQuery = None,
         poll: Poll = None,
         poll_answer: PollAnswer = None,
+        my_chat_member: ChatMemberUpdated = None,
+        chat_member: ChatMemberUpdated = None,
         **_kwargs: Any,
     ):
         # Required
@@ -127,6 +156,8 @@ def __init__(
         self.edited_channel_post = edited_channel_post
         self.poll = poll
         self.poll_answer = poll_answer
+        self.my_chat_member = my_chat_member
+        self.chat_member = chat_member
 
         self._effective_user: Optional['User'] = None
         self._effective_chat: Optional['Chat'] = None
@@ -170,6 +201,12 @@ def effective_user(self) -> Optional['User']:
         elif self.poll_answer:
             user = self.poll_answer.user
 
+        elif self.my_chat_member:
+            user = self.my_chat_member.from_user
+
+        elif self.chat_member:
+            user = self.chat_member.from_user
+
         self._effective_user = user
         return user
 
@@ -203,6 +240,12 @@ def effective_chat(self) -> Optional['Chat']:
         elif self.edited_channel_post:
             chat = self.edited_channel_post.chat
 
+        elif self.my_chat_member:
+            chat = self.my_chat_member.chat
+
+        elif self.chat_member:
+            chat = self.chat_member.chat
+
         self._effective_chat = chat
         return chat
 
@@ -259,5 +302,7 @@ def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Update']:
         data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot)
         data['poll'] = Poll.de_json(data.get('poll'), bot)
         data['poll_answer'] = PollAnswer.de_json(data.get('poll_answer'), bot)
+        data['my_chat_member'] = ChatMemberUpdated.de_json(data.get('my_chat_member'), bot)
+        data['chat_member'] = ChatMemberUpdated.de_json(data.get('chat_member'), bot)
 
         return cls(**data)
diff --git a/telegram/voicechat.py b/telegram/voicechat.py
new file mode 100644
index 00000000000..1f9d752331a
--- /dev/null
+++ b/telegram/voicechat.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# pylint: disable=R0903
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+"""This module contains objects related to Telegram voice chats."""
+
+from typing import TYPE_CHECKING, Any, Optional, List
+
+from telegram import TelegramObject, User
+from telegram.utils.types import JSONDict
+
+if TYPE_CHECKING:
+    from telegram import Bot
+
+
+class VoiceChatStarted(TelegramObject):
+    """
+    This object represents a service message about a voice
+    chat started in the chat. Currently holds no information.
+
+    .. versionadded:: 13.4
+    """
+
+    def __init__(self, **_kwargs: Any):
+        pass
+
+
+class VoiceChatEnded(TelegramObject):
+    """
+    This object represents a service message about a
+    voice chat ended in the chat.
+
+    Objects of this class are comparable in terms of equality.
+    Two objects of this class are considered equal, if their
+    :attr:`duration` are equal.
+
+    .. versionadded:: 13.4
+
+    Args:
+        duration (:obj:`int`): Voice chat duration in seconds.
+
+    Attributes:
+        duration (:obj:`int`): Voice chat duration in seconds.
+
+    """
+
+    def __init__(self, duration: int, **_kwargs: Any) -> None:
+        self.duration = int(duration) if duration is not None else None
+        self._id_attrs = (self.duration,)
+
+
+class VoiceChatParticipantsInvited(TelegramObject):
+    """
+    This object represents a service message about
+    new members invited to a voice chat.
+
+    Objects of this class are comparable in terms of equality.
+    Two objects of this class are considered equal, if their
+    :attr:`users` are equal.
+
+    .. versionadded:: 13.4
+
+    Args:
+        users (List[:class:`telegram.User`]):  New members that
+            were invited to the voice chat.
+
+    Attributes:
+        users (List[:class:`telegram.User`]):  New members that
+            were invited to the voice chat.
+
+    """
+
+    def __init__(self, users: List[User], **_kwargs: Any) -> None:
+        self.users = users
+        self._id_attrs = (self.users,)
+
+    def __hash__(self) -> int:
+        return hash(tuple(self.users))
+
+    @classmethod
+    def de_json(
+        cls, data: Optional[JSONDict], bot: 'Bot'
+    ) -> Optional['VoiceChatParticipantsInvited']:
+        data = cls.parse_data(data)
+
+        if not data:
+            return None
+
+        data['users'] = User.de_list(data.get('users', []), bot)
+        return cls(**data)
+
+    def to_dict(self) -> JSONDict:
+        data = super().to_dict()
+
+        data["users"] = [u.to_dict() for u in self.users]
+        return data
diff --git a/tests/test_bot.py b/tests/test_bot.py
index 48d33e61223..ade61f6d525 100644
--- a/tests/test_bot.py
+++ b/tests/test_bot.py
@@ -868,13 +868,14 @@ def _post(*args, **kwargs):
         assert bot.token not in resulting_path
         assert resulting_path == path
 
-    # TODO: Needs improvement. No feasable way to test until bots can add members.
+    # TODO: Needs improvement. No feasible way to test until bots can add members.
     def test_kick_chat_member(self, monkeypatch, bot):
         def test(url, data, *args, **kwargs):
             chat_id = data['chat_id'] == 2
             user_id = data['user_id'] == 32
             until_date = data.get('until_date', 1577887200) == 1577887200
-            return chat_id and user_id and until_date
+            revoke_msgs = data.get('revoke_messages', True) is True
+            return chat_id and user_id and until_date and revoke_msgs
 
         monkeypatch.setattr(bot.request, 'post', test)
         until = from_timestamp(1577887200)
@@ -882,6 +883,7 @@ def test(url, data, *args, **kwargs):
         assert bot.kick_chat_member(2, 32)
         assert bot.kick_chat_member(2, 32, until_date=until)
         assert bot.kick_chat_member(2, 32, until_date=1577887200)
+        assert bot.kick_chat_member(2, 32, revoke_messages=True)
 
     def test_kick_chat_member_default_tz(self, monkeypatch, tz_bot):
         until = dtm.datetime(2020, 1, 11, 16, 13)
@@ -1512,6 +1514,8 @@ def test_promote_chat_member(self, bot, channel_id):
                 can_restrict_members=True,
                 can_pin_messages=True,
                 can_promote_members=True,
+                can_manage_chat=True,
+                can_manage_voice_chats=True,
             )
 
     @flaky(3, 1)
@@ -1522,6 +1526,33 @@ def test_export_chat_invite_link(self, bot, channel_id):
         assert isinstance(invite_link, str)
         assert invite_link != ''
 
+    @flaky(3, 1)
+    @pytest.mark.timeout(10)
+    def test_advanced_chat_invite_links(self, bot, channel_id):
+        # we are testing this all in one function in order to save api calls
+        timestamp = dtm.datetime.utcnow()
+        add_seconds = dtm.timedelta(0, 70)
+        time_in_future = timestamp + add_seconds
+        invite_link = bot.create_chat_invite_link(
+            channel_id, expire_date=time_in_future, member_limit=10
+        )
+        assert invite_link.invite_link != ''
+        assert invite_link.expire_date == to_timestamp(time_in_future)
+        assert invite_link.member_limit == 10
+
+        add_seconds = dtm.timedelta(0, 80)
+        time_in_future = timestamp + add_seconds
+        edited_invite_link = bot.edit_chat_invite_link(
+            channel_id, invite_link.invite_link, expire_date=time_in_future, member_limit=20
+        )
+        assert edited_invite_link.invite_link == invite_link.invite_link
+        assert edited_invite_link.expire_date == to_timestamp(time_in_future)
+        assert edited_invite_link.member_limit == 20
+
+        revoked_invite_link = bot.revoke_chat_invite_link(channel_id, invite_link.invite_link)
+        assert revoked_invite_link.invite_link == invite_link.invite_link
+        assert revoked_invite_link.is_revoked is True
+
     @flaky(3, 1)
     @pytest.mark.timeout(10)
     def test_set_chat_photo(self, bot, channel_id):
diff --git a/tests/test_chat.py b/tests/test_chat.py
index 5d313cf1898..bde3883f7f4 100644
--- a/tests/test_chat.py
+++ b/tests/test_chat.py
@@ -37,6 +37,7 @@ def chat(bot):
         can_set_sticker_set=TestChat.can_set_sticker_set,
         permissions=TestChat.permissions,
         slow_mode_delay=TestChat.slow_mode_delay,
+        message_auto_delete_time=TestChat.message_auto_delete_time,
         bio=TestChat.bio,
         linked_chat_id=TestChat.linked_chat_id,
         location=TestChat.location,
@@ -57,6 +58,7 @@ class TestChat:
         can_invite_users=True,
     )
     slow_mode_delay = 30
+    message_auto_delete_time = 42
     bio = "I'm a Barbie Girl in a Barbie World"
     linked_chat_id = 11880
     location = ChatLocation(Location(123, 456), 'Barbie World')
@@ -72,6 +74,7 @@ def test_de_json(self, bot):
             'can_set_sticker_set': self.can_set_sticker_set,
             'permissions': self.permissions.to_dict(),
             'slow_mode_delay': self.slow_mode_delay,
+            'message_auto_delete_time': self.message_auto_delete_time,
             'bio': self.bio,
             'linked_chat_id': self.linked_chat_id,
             'location': self.location.to_dict(),
@@ -87,6 +90,7 @@ def test_de_json(self, bot):
         assert chat.can_set_sticker_set == self.can_set_sticker_set
         assert chat.permissions == self.permissions
         assert chat.slow_mode_delay == self.slow_mode_delay
+        assert chat.message_auto_delete_time == self.message_auto_delete_time
         assert chat.bio == self.bio
         assert chat.linked_chat_id == self.linked_chat_id
         assert chat.location.location == self.location.location
@@ -103,6 +107,7 @@ def test_to_dict(self, chat):
         assert chat_dict['all_members_are_administrators'] == chat.all_members_are_administrators
         assert chat_dict['permissions'] == chat.permissions.to_dict()
         assert chat_dict['slow_mode_delay'] == chat.slow_mode_delay
+        assert chat_dict['message_auto_delete_time'] == chat.message_auto_delete_time
         assert chat_dict['bio'] == chat.bio
         assert chat_dict['linked_chat_id'] == chat.linked_chat_id
         assert chat_dict['location'] == chat.location.to_dict()
@@ -556,6 +561,62 @@ def make_assertion(*_, **kwargs):
         monkeypatch.setattr(chat.bot, 'copy_message', make_assertion)
         assert chat.copy_message(chat_id='test_copy', message_id=42)
 
+    def test_export_invite_link(self, monkeypatch, chat):
+        def make_assertion(*_, **kwargs):
+            return kwargs['chat_id'] == chat.id
+
+        assert check_shortcut_signature(
+            Chat.export_invite_link, Bot.export_chat_invite_link, ['chat_id'], []
+        )
+        assert check_shortcut_call(chat.export_invite_link, chat.bot, 'export_chat_invite_link')
+        assert check_defaults_handling(chat.export_invite_link, chat.bot)
+
+        monkeypatch.setattr(chat.bot, 'export_chat_invite_link', make_assertion)
+        assert chat.export_invite_link()
+
+    def test_create_invite_link(self, monkeypatch, chat):
+        def make_assertion(*_, **kwargs):
+            return kwargs['chat_id'] == chat.id
+
+        assert check_shortcut_signature(
+            Chat.create_invite_link, Bot.create_chat_invite_link, ['chat_id'], []
+        )
+        assert check_shortcut_call(chat.create_invite_link, chat.bot, 'create_chat_invite_link')
+        assert check_defaults_handling(chat.create_invite_link, chat.bot)
+
+        monkeypatch.setattr(chat.bot, 'create_chat_invite_link', make_assertion)
+        assert chat.create_invite_link()
+
+    def test_edit_invite_link(self, monkeypatch, chat):
+        link = "ThisIsALink"
+
+        def make_assertion(*_, **kwargs):
+            return kwargs['chat_id'] == chat.id and kwargs['invite_link'] == link
+
+        assert check_shortcut_signature(
+            Chat.edit_invite_link, Bot.edit_chat_invite_link, ['chat_id'], []
+        )
+        assert check_shortcut_call(chat.edit_invite_link, chat.bot, 'edit_chat_invite_link')
+        assert check_defaults_handling(chat.edit_invite_link, chat.bot)
+
+        monkeypatch.setattr(chat.bot, 'edit_chat_invite_link', make_assertion)
+        assert chat.edit_invite_link(invite_link=link)
+
+    def test_revoke_invite_link(self, monkeypatch, chat):
+        link = "ThisIsALink"
+
+        def make_assertion(*_, **kwargs):
+            return kwargs['chat_id'] == chat.id and kwargs['invite_link'] == link
+
+        assert check_shortcut_signature(
+            Chat.revoke_invite_link, Bot.revoke_chat_invite_link, ['chat_id'], []
+        )
+        assert check_shortcut_call(chat.revoke_invite_link, chat.bot, 'revoke_chat_invite_link')
+        assert check_defaults_handling(chat.revoke_invite_link, chat.bot)
+
+        monkeypatch.setattr(chat.bot, 'revoke_chat_invite_link', make_assertion)
+        assert chat.revoke_invite_link(invite_link=link)
+
     def test_equality(self):
         a = Chat(self.id_, self.title, self.type_)
         b = Chat(self.id_, self.title, self.type_)
diff --git a/tests/test_chatinvitelink.py b/tests/test_chatinvitelink.py
new file mode 100644
index 00000000000..ecf3262a7c0
--- /dev/null
+++ b/tests/test_chatinvitelink.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+import datetime
+
+import pytest
+
+from telegram import User, ChatInviteLink
+from telegram.utils.helpers import to_timestamp
+
+
+@pytest.fixture(scope='class')
+def creator():
+    return User(1, 'First name', False)
+
+
+@pytest.fixture(scope='class')
+def invite_link(creator):
+    return ChatInviteLink(
+        TestChatInviteLink.link, creator, TestChatInviteLink.primary, TestChatInviteLink.revoked
+    )
+
+
+class TestChatInviteLink:
+
+    link = "thisialink"
+    primary = True
+    revoked = False
+
+    def test_de_json_required_args(self, bot, creator):
+        json_dict = {
+            'invite_link': self.link,
+            'creator': creator.to_dict(),
+            'is_primary': self.primary,
+            'is_revoked': self.revoked,
+        }
+
+        invite_link = ChatInviteLink.de_json(json_dict, bot)
+
+        assert invite_link.invite_link == self.link
+        assert invite_link.creator == creator
+        assert invite_link.is_primary == self.primary
+        assert invite_link.is_revoked == self.revoked
+
+    def test_de_json_all_args(self, bot, creator):
+        time = datetime.datetime.utcnow()
+        member_limit = 200
+
+        json_dict = {
+            'invite_link': self.link,
+            'creator': creator.to_dict(),
+            'is_primary': self.primary,
+            'is_revoked': self.revoked,
+            'expire_date': to_timestamp(time),
+            'member_limit': member_limit,
+        }
+
+        invite_link = ChatInviteLink.de_json(json_dict, bot)
+
+        assert invite_link.invite_link == self.link
+        assert invite_link.creator == creator
+        assert invite_link.is_primary == self.primary
+        assert invite_link.is_revoked == self.revoked
+        assert invite_link.expire_date == to_timestamp(time)
+        assert invite_link.member_limit == member_limit
+
+    def test_to_dict(self, invite_link):
+        invite_link_dict = invite_link.to_dict()
+        assert isinstance(invite_link_dict, dict)
+        assert invite_link_dict['creator'] == invite_link.creator.to_dict()
+        assert invite_link_dict['invite_link'] == invite_link.invite_link
+
+    def test_equality(self):
+        a = ChatInviteLink("link", User(1, '', False), False, True)
+        b = ChatInviteLink("link", User(1, '', False), True, True)
+        d = ChatInviteLink("link", User(2, '', False), False, True)
+        d2 = ChatInviteLink("notalink", User(1, '', False), False, True)
+        d3 = ChatInviteLink("notalink", User(1, '', False), True, True)
+
+        assert a == b
+        assert hash(a) == hash(b)
+        assert a is not b
+
+        assert a != d
+        assert hash(a) != hash(d)
+
+        assert a != d2
+        assert hash(a) != hash(d2)
+
+        assert d2 != d3
+        assert hash(d2) != hash(d3)
diff --git a/tests/test_chatmember.py b/tests/test_chatmember.py
index 65c4b1d0518..e6e34d0e79e 100644
--- a/tests/test_chatmember.py
+++ b/tests/test_chatmember.py
@@ -69,6 +69,8 @@ def test_de_json_all_args(self, bot, user):
             'can_send_polls': False,
             'can_send_other_messages': True,
             'can_add_web_page_previews': False,
+            'can_manage_chat': True,
+            'can_manage_voice_chats': True,
         }
 
         chat_member = ChatMember.de_json(json_dict, bot)
@@ -91,6 +93,8 @@ def test_de_json_all_args(self, bot, user):
         assert chat_member.can_send_polls is False
         assert chat_member.can_send_other_messages is True
         assert chat_member.can_add_web_page_previews is False
+        assert chat_member.can_manage_chat is True
+        assert chat_member.can_manage_voice_chats is True
 
     def test_to_dict(self, chat_member):
         chat_member_dict = chat_member.to_dict()
diff --git a/tests/test_chatmemberhandler.py b/tests/test_chatmemberhandler.py
new file mode 100644
index 00000000000..ba177b7070c
--- /dev/null
+++ b/tests/test_chatmemberhandler.py
@@ -0,0 +1,220 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+import time
+from queue import Queue
+
+import pytest
+
+from telegram import (
+    Update,
+    Bot,
+    Message,
+    User,
+    Chat,
+    CallbackQuery,
+    ChosenInlineResult,
+    ShippingQuery,
+    PreCheckoutQuery,
+    ChatMemberUpdated,
+    ChatMember,
+)
+from telegram.ext import CallbackContext, JobQueue, ChatMemberHandler
+from telegram.utils.helpers import from_timestamp
+
+message = Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
+
+params = [
+    {'message': message},
+    {'edited_message': message},
+    {'callback_query': CallbackQuery(1, User(1, '', False), 'chat', message=message)},
+    {'channel_post': message},
+    {'edited_channel_post': message},
+    {'chosen_inline_result': ChosenInlineResult('id', User(1, '', False), '')},
+    {'shipping_query': ShippingQuery('id', User(1, '', False), '', None)},
+    {'pre_checkout_query': PreCheckoutQuery('id', User(1, '', False), '', 0, '')},
+    {'callback_query': CallbackQuery(1, User(1, '', False), 'chat')},
+]
+
+ids = (
+    'message',
+    'edited_message',
+    'callback_query',
+    'channel_post',
+    'edited_channel_post',
+    'chosen_inline_result',
+    'shipping_query',
+    'pre_checkout_query',
+    'callback_query_without_message',
+)
+
+
+@pytest.fixture(scope='class', params=params, ids=ids)
+def false_update(request):
+    return Update(update_id=2, **request.param)
+
+
+@pytest.fixture(scope='class')
+def chat_member_updated():
+    return ChatMemberUpdated(
+        Chat(1, 'chat'),
+        User(1, '', False),
+        from_timestamp(int(time.time())),
+        ChatMember(User(1, '', False), ChatMember.CREATOR),
+        ChatMember(User(1, '', False), ChatMember.CREATOR),
+    )
+
+
+@pytest.fixture(scope='function')
+def chat_member(bot, chat_member_updated):
+    return Update(0, my_chat_member=chat_member_updated)
+
+
+class TestChatMemberHandler:
+    test_flag = False
+
+    @pytest.fixture(autouse=True)
+    def reset(self):
+        self.test_flag = False
+
+    def callback_basic(self, bot, update):
+        test_bot = isinstance(bot, Bot)
+        test_update = isinstance(update, Update)
+        self.test_flag = test_bot and test_update
+
+    def callback_data_1(self, bot, update, user_data=None, chat_data=None):
+        self.test_flag = (user_data is not None) or (chat_data is not None)
+
+    def callback_data_2(self, bot, update, user_data=None, chat_data=None):
+        self.test_flag = (user_data is not None) and (chat_data is not None)
+
+    def callback_queue_1(self, bot, update, job_queue=None, update_queue=None):
+        self.test_flag = (job_queue is not None) or (update_queue is not None)
+
+    def callback_queue_2(self, bot, update, job_queue=None, update_queue=None):
+        self.test_flag = (job_queue is not None) and (update_queue is not None)
+
+    def callback_context(self, update, context):
+        self.test_flag = (
+            isinstance(context, CallbackContext)
+            and isinstance(context.bot, Bot)
+            and isinstance(update, Update)
+            and isinstance(context.update_queue, Queue)
+            and isinstance(context.job_queue, JobQueue)
+            and isinstance(context.user_data, dict)
+            and isinstance(context.chat_data, dict)
+            and isinstance(context.bot_data, dict)
+            and isinstance(update.chat_member or update.my_chat_member, ChatMemberUpdated)
+        )
+
+    def test_basic(self, dp, chat_member):
+        handler = ChatMemberHandler(self.callback_basic)
+        dp.add_handler(handler)
+
+        assert handler.check_update(chat_member)
+
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+    @pytest.mark.parametrize(
+        argnames=['allowed_types', 'expected'],
+        argvalues=[
+            (ChatMemberHandler.MY_CHAT_MEMBER, (True, False)),
+            (ChatMemberHandler.CHAT_MEMBER, (False, True)),
+            (ChatMemberHandler.ANY_CHAT_MEMBER, (True, True)),
+        ],
+        ids=['MY_CHAT_MEMBER', 'CHAT_MEMBER', 'ANY_CHAT_MEMBER'],
+    )
+    def test_chat_member_types(
+        self, dp, chat_member_updated, chat_member, expected, allowed_types
+    ):
+        result_1, result_2 = expected
+
+        handler = ChatMemberHandler(self.callback_basic, chat_member_types=allowed_types)
+        dp.add_handler(handler)
+
+        assert handler.check_update(chat_member) == result_1
+        dp.process_update(chat_member)
+        assert self.test_flag == result_1
+
+        self.test_flag = False
+        chat_member.my_chat_member = None
+        chat_member.chat_member = chat_member_updated
+
+        assert handler.check_update(chat_member) == result_2
+        dp.process_update(chat_member)
+        assert self.test_flag == result_2
+
+    def test_pass_user_or_chat_data(self, dp, chat_member):
+        handler = ChatMemberHandler(self.callback_data_1, pass_user_data=True)
+        dp.add_handler(handler)
+
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+        dp.remove_handler(handler)
+        handler = ChatMemberHandler(self.callback_data_1, pass_chat_data=True)
+        dp.add_handler(handler)
+
+        self.test_flag = False
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+        dp.remove_handler(handler)
+        handler = ChatMemberHandler(self.callback_data_2, pass_chat_data=True, pass_user_data=True)
+        dp.add_handler(handler)
+
+        self.test_flag = False
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+    def test_pass_job_or_update_queue(self, dp, chat_member):
+        handler = ChatMemberHandler(self.callback_queue_1, pass_job_queue=True)
+        dp.add_handler(handler)
+
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+        dp.remove_handler(handler)
+        handler = ChatMemberHandler(self.callback_queue_1, pass_update_queue=True)
+        dp.add_handler(handler)
+
+        self.test_flag = False
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+        dp.remove_handler(handler)
+        handler = ChatMemberHandler(
+            self.callback_queue_2, pass_job_queue=True, pass_update_queue=True
+        )
+        dp.add_handler(handler)
+
+        self.test_flag = False
+        dp.process_update(chat_member)
+        assert self.test_flag
+
+    def test_other_update_types(self, false_update):
+        handler = ChatMemberHandler(self.callback_basic)
+        assert not handler.check_update(false_update)
+
+    def test_context(self, cdp, chat_member):
+        handler = ChatMemberHandler(self.callback_context)
+        cdp.add_handler(handler)
+
+        cdp.process_update(chat_member)
+        assert self.test_flag
diff --git a/tests/test_chatmemberupdated.py b/tests/test_chatmemberupdated.py
new file mode 100644
index 00000000000..1f3bd28c9e8
--- /dev/null
+++ b/tests/test_chatmemberupdated.py
@@ -0,0 +1,177 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+import datetime
+
+import pytest
+import pytz
+
+from telegram import User, ChatMember, Chat, ChatMemberUpdated, ChatInviteLink
+from telegram.utils.helpers import to_timestamp
+
+
+@pytest.fixture(scope='class')
+def user():
+    return User(1, 'First name', False)
+
+
+@pytest.fixture(scope='class')
+def chat():
+    return Chat(1, Chat.SUPERGROUP, 'Chat')
+
+
+@pytest.fixture(scope='class')
+def old_chat_member(user):
+    return ChatMember(user, TestChatMemberUpdated.old_status)
+
+
+@pytest.fixture(scope='class')
+def new_chat_member(user):
+    return ChatMember(user, TestChatMemberUpdated.new_status)
+
+
+@pytest.fixture(scope='class')
+def time():
+    return datetime.datetime.now(tz=pytz.utc)
+
+
+@pytest.fixture(scope='class')
+def invite_link(user):
+    return ChatInviteLink('link', user, True, True)
+
+
+@pytest.fixture(scope='class')
+def chat_member_updated(user, chat, old_chat_member, new_chat_member, invite_link, time):
+    return ChatMemberUpdated(chat, user, time, old_chat_member, new_chat_member, invite_link)
+
+
+class TestChatMemberUpdated:
+    old_status = ChatMember.MEMBER
+    new_status = ChatMember.ADMINISTRATOR
+
+    def test_de_json_required_args(self, bot, user, chat, old_chat_member, new_chat_member, time):
+        json_dict = {
+            'chat': chat.to_dict(),
+            'from': user.to_dict(),
+            'date': to_timestamp(time),
+            'old_chat_member': old_chat_member.to_dict(),
+            'new_chat_member': new_chat_member.to_dict(),
+        }
+
+        chat_member_updated = ChatMemberUpdated.de_json(json_dict, bot)
+
+        assert chat_member_updated.chat == chat
+        assert chat_member_updated.from_user == user
+        assert pytest.approx(chat_member_updated.date == time)
+        assert to_timestamp(chat_member_updated.date) == to_timestamp(time)
+        assert chat_member_updated.old_chat_member == old_chat_member
+        assert chat_member_updated.new_chat_member == new_chat_member
+        assert chat_member_updated.invite_link is None
+
+    def test_de_json_all_args(
+        self, bot, user, time, invite_link, chat, old_chat_member, new_chat_member
+    ):
+        json_dict = {
+            'chat': chat.to_dict(),
+            'from': user.to_dict(),
+            'date': to_timestamp(time),
+            'old_chat_member': old_chat_member.to_dict(),
+            'new_chat_member': new_chat_member.to_dict(),
+            'invite_link': invite_link.to_dict(),
+        }
+
+        chat_member_updated = ChatMemberUpdated.de_json(json_dict, bot)
+
+        assert chat_member_updated.chat == chat
+        assert chat_member_updated.from_user == user
+        assert pytest.approx(chat_member_updated.date == time)
+        assert to_timestamp(chat_member_updated.date) == to_timestamp(time)
+        assert chat_member_updated.old_chat_member == old_chat_member
+        assert chat_member_updated.new_chat_member == new_chat_member
+        assert chat_member_updated.invite_link == invite_link
+
+    def test_to_dict(self, chat_member_updated):
+        chat_member_updated_dict = chat_member_updated.to_dict()
+        assert isinstance(chat_member_updated_dict, dict)
+        assert chat_member_updated_dict['chat'] == chat_member_updated.chat.to_dict()
+        assert chat_member_updated_dict['from'] == chat_member_updated.from_user.to_dict()
+        assert chat_member_updated_dict['date'] == to_timestamp(chat_member_updated.date)
+        assert (
+            chat_member_updated_dict['old_chat_member']
+            == chat_member_updated.old_chat_member.to_dict()
+        )
+        assert (
+            chat_member_updated_dict['new_chat_member']
+            == chat_member_updated.new_chat_member.to_dict()
+        )
+        assert chat_member_updated_dict['invite_link'] == chat_member_updated.invite_link.to_dict()
+
+    def test_equality(self, time, old_chat_member, new_chat_member, invite_link):
+        a = ChatMemberUpdated(
+            Chat(1, 'chat'),
+            User(1, '', False),
+            time,
+            old_chat_member,
+            new_chat_member,
+            invite_link,
+        )
+        b = ChatMemberUpdated(
+            Chat(1, 'chat'), User(1, '', False), time, old_chat_member, new_chat_member
+        )
+        # wrong date
+        c = ChatMemberUpdated(
+            Chat(1, 'chat'),
+            User(1, '', False),
+            time + datetime.timedelta(hours=1),
+            old_chat_member,
+            new_chat_member,
+        )
+        # wrong chat & form_user
+        d = ChatMemberUpdated(
+            Chat(42, 'wrong_chat'),
+            User(42, 'wrong_user', False),
+            time,
+            old_chat_member,
+            new_chat_member,
+        )
+        # wrong old_chat_member
+        e = ChatMemberUpdated(
+            Chat(1, 'chat'),
+            User(1, '', False),
+            time,
+            ChatMember(User(1, '', False), ChatMember.CREATOR),
+            new_chat_member,
+        )
+        # wrong new_chat_member
+        f = ChatMemberUpdated(
+            Chat(1, 'chat'),
+            User(1, '', False),
+            time,
+            old_chat_member,
+            ChatMember(User(1, '', False), ChatMember.CREATOR),
+        )
+        # wrong type
+        g = ChatMember(User(1, '', False), ChatMember.CREATOR)
+
+        assert a == b
+        assert hash(a) == hash(b)
+        assert a is not b
+
+        for other in [c, d, e, f, g]:
+            assert a != other
+            assert hash(a) != hash(other)
diff --git a/tests/test_filters.py b/tests/test_filters.py
index f8d95edad45..2943d19a005 100644
--- a/tests/test_filters.py
+++ b/tests/test_filters.py
@@ -44,7 +44,7 @@ def update():
 
 @pytest.fixture(scope='function', params=MessageEntity.ALL_TYPES)
 def message_entity(request):
-    return MessageEntity(request.param, 0, 0, url='', user='')
+    return MessageEntity(request.param, 0, 0, url='', user=User(1, 'first_name', False))
 
 
 @pytest.fixture(
@@ -828,6 +828,11 @@ def test_filters_status_update(self, update):
         assert Filters.status_update.chat_created(update)
         update.message.channel_chat_created = False
 
+        update.message.message_auto_delete_timer_changed = True
+        assert Filters.status_update(update)
+        assert Filters.status_update.message_auto_delete_timer_changed(update)
+        update.message.message_auto_delete_timer_changed = False
+
         update.message.migrate_to_chat_id = 100
         assert Filters.status_update(update)
         assert Filters.status_update.migrate(update)
@@ -853,6 +858,21 @@ def test_filters_status_update(self, update):
         assert Filters.status_update.proximity_alert_triggered(update)
         update.message.proximity_alert_triggered = None
 
+        update.message.voice_chat_started = 'hello'
+        assert Filters.status_update(update)
+        assert Filters.status_update.voice_chat_started(update)
+        update.message.voice_chat_started = None
+
+        update.message.voice_chat_ended = 'bye'
+        assert Filters.status_update(update)
+        assert Filters.status_update.voice_chat_ended(update)
+        update.message.voice_chat_ended = None
+
+        update.message.voice_chat_participants_invited = 'invited'
+        assert Filters.status_update(update)
+        assert Filters.status_update.voice_chat_participants_invited(update)
+        update.message.voice_chat_participants_invited = None
+
     def test_filters_forwarded(self, update):
         assert not Filters.forwarded(update)
         update.message.forward_date = datetime.datetime.utcnow()
@@ -1453,6 +1473,13 @@ def test_filters_dice_type(self, update):
         assert not Filters.dice.darts(update)
         assert not Filters.dice.slot_machine([4])(update)
 
+        update.message.dice = Dice(5, '🎳')
+        assert Filters.dice.bowling(update)
+        assert Filters.dice.bowling([4, 5])(update)
+        assert not Filters.dice.dice(update)
+        assert not Filters.dice.darts(update)
+        assert not Filters.dice.football([4])(update)
+
     def test_language_filter_single(self, update):
         update.message.from_user.language_code = 'en_US'
         assert (Filters.language('en_US'))(update)
diff --git a/tests/test_message.py b/tests/test_message.py
index 2959f81d678..638718d9b73 100644
--- a/tests/test_message.py
+++ b/tests/test_message.py
@@ -48,6 +48,10 @@
     Dice,
     Bot,
     ChatAction,
+    VoiceChatStarted,
+    VoiceChatEnded,
+    VoiceChatParticipantsInvited,
+    MessageAutoDeleteTimerChanged,
 )
 from telegram.ext import Defaults
 from tests.conftest import check_shortcut_signature, check_shortcut_call, check_defaults_handling
@@ -115,6 +119,7 @@ def message(bot):
         {'group_chat_created': True},
         {'supergroup_chat_created': True},
         {'channel_chat_created': True},
+        {'message_auto_delete_timer_changed': MessageAutoDeleteTimerChanged(42)},
         {'migrate_to_chat_id': -12345},
         {'migrate_from_chat_id': -54321},
         {'pinned_message': Message(7, None, None, None)},
@@ -166,6 +171,13 @@ def message(bot):
                 User(1, 'John', False), User(2, 'Doe', False), 42
             )
         },
+        {'voice_chat_started': VoiceChatStarted()},
+        {'voice_chat_ended': VoiceChatEnded(100)},
+        {
+            'voice_chat_participants_invited': VoiceChatParticipantsInvited(
+                [User(1, 'Rem', False), User(2, 'Emilia', False)]
+            )
+        },
         {'sender_chat': Chat(-123, 'discussion_channel')},
     ],
     ids=[
@@ -195,6 +207,7 @@ def message(bot):
         'group_created',
         'supergroup_created',
         'channel_created',
+        'message_auto_delete_timer_changed',
         'migrated_to',
         'migrated_from',
         'pinned',
@@ -211,6 +224,9 @@ def message(bot):
         'dice',
         'via_bot',
         'proximity_alert_triggered',
+        'voice_chat_started',
+        'voice_chat_ended',
+        'voice_chat_participants_invited',
         'sender_chat',
     ],
 )
diff --git a/tests/test_messageautodeletetimerchanged.py b/tests/test_messageautodeletetimerchanged.py
new file mode 100644
index 00000000000..22b44ba5446
--- /dev/null
+++ b/tests/test_messageautodeletetimerchanged.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+
+from telegram import MessageAutoDeleteTimerChanged, VoiceChatEnded
+
+
+class TestMessageAutoDeleteTimerChanged:
+    message_auto_delete_time = 100
+
+    def test_de_json(self):
+        json_dict = {'message_auto_delete_time': self.message_auto_delete_time}
+        madtc = MessageAutoDeleteTimerChanged.de_json(json_dict, None)
+
+        assert madtc.message_auto_delete_time == self.message_auto_delete_time
+
+    def test_to_dict(self):
+        madtc = MessageAutoDeleteTimerChanged(self.message_auto_delete_time)
+        madtc_dict = madtc.to_dict()
+
+        assert isinstance(madtc_dict, dict)
+        assert madtc_dict["message_auto_delete_time"] == self.message_auto_delete_time
+
+    def test_equality(self):
+        a = MessageAutoDeleteTimerChanged(100)
+        b = MessageAutoDeleteTimerChanged(100)
+        c = MessageAutoDeleteTimerChanged(50)
+        d = VoiceChatEnded(25)
+
+        assert a == b
+        assert hash(a) == hash(b)
+
+        assert a != c
+        assert hash(a) != hash(c)
+
+        assert a != d
+        assert hash(a) != hash(d)
diff --git a/tests/test_update.py b/tests/test_update.py
index 4a929ddfccd..10326396991 100644
--- a/tests/test_update.py
+++ b/tests/test_update.py
@@ -16,6 +16,7 @@
 #
 # You should have received a copy of the GNU Lesser Public License
 # along with this program.  If not, see [http://www.gnu.org/licenses/].
+import time
 
 import pytest
 
@@ -31,10 +32,20 @@
     PreCheckoutQuery,
     Poll,
     PollOption,
+    ChatMemberUpdated,
+    ChatMember,
 )
 from telegram.poll import PollAnswer
+from telegram.utils.helpers import from_timestamp
 
 message = Message(1, None, Chat(1, ''), from_user=User(1, '', False), text='Text')
+chat_member_updated = ChatMemberUpdated(
+    Chat(1, 'chat'),
+    User(1, '', False),
+    from_timestamp(int(time.time())),
+    ChatMember(User(1, '', False), ChatMember.CREATOR),
+    ChatMember(User(1, '', False), ChatMember.CREATOR),
+)
 
 params = [
     {'message': message},
@@ -49,6 +60,8 @@
     {'callback_query': CallbackQuery(1, User(1, '', False), 'chat')},
     {'poll': Poll('id', '?', [PollOption('.', 1)], False, False, False, Poll.REGULAR, True)},
     {'poll_answer': PollAnswer("id", User(1, '', False), [1])},
+    {'my_chat_member': chat_member_updated},
+    {'chat_member': chat_member_updated},
 ]
 
 all_types = (
@@ -63,6 +76,8 @@
     'pre_checkout_query',
     'poll',
     'poll_answer',
+    'my_chat_member',
+    'chat_member',
 )
 
 ids = all_types + ('callback_query_without_message',)
@@ -146,6 +161,8 @@ def test_effective_message(self, update):
             or update.pre_checkout_query is not None
             or update.poll is not None
             or update.poll_answer is not None
+            or update.my_chat_member is not None
+            or update.chat_member is not None
         ):
             assert eff_message.message_id == message.message_id
         else:
diff --git a/tests/test_voicechat.py b/tests/test_voicechat.py
new file mode 100644
index 00000000000..1d0e1aeccd8
--- /dev/null
+++ b/tests/test_voicechat.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+
+import pytest
+
+from telegram import VoiceChatStarted, VoiceChatEnded, VoiceChatParticipantsInvited, User
+
+
+@pytest.fixture(scope='class')
+def user1():
+    return User(first_name='Misses Test', id=123, is_bot=False)
+
+
+@pytest.fixture(scope='class')
+def user2():
+    return User(first_name='Mister Test', id=124, is_bot=False)
+
+
+class TestVoiceChatStarted:
+    def test_de_json(self):
+        voice_chat_started = VoiceChatStarted.de_json({}, None)
+        assert isinstance(voice_chat_started, VoiceChatStarted)
+
+    def test_to_dict(self):
+        voice_chat_started = VoiceChatStarted()
+        voice_chat_dict = voice_chat_started.to_dict()
+        assert voice_chat_dict == {}
+
+
+class TestVoiceChatEnded:
+    duration = 100
+
+    def test_de_json(self):
+        json_dict = {'duration': self.duration}
+        voice_chat_ended = VoiceChatEnded.de_json(json_dict, None)
+
+        assert voice_chat_ended.duration == self.duration
+
+    def test_to_dict(self):
+        voice_chat_ended = VoiceChatEnded(self.duration)
+        voice_chat_dict = voice_chat_ended.to_dict()
+
+        assert isinstance(voice_chat_dict, dict)
+        assert voice_chat_dict["duration"] == self.duration
+
+    def test_equality(self):
+        a = VoiceChatEnded(100)
+        b = VoiceChatEnded(100)
+        c = VoiceChatEnded(50)
+        d = VoiceChatEnded(25)
+
+        assert a == b
+        assert hash(a) == hash(b)
+
+        assert a != c
+        assert hash(a) != hash(c)
+
+        assert a != d
+        assert hash(a) != hash(d)
+
+
+class TestVoiceChatParticipantsInvited:
+    def test_de_json(self, user1, user2, bot):
+        json_data = {"users": [user1.to_dict(), user2.to_dict()]}
+        voice_chat_participants = VoiceChatParticipantsInvited.de_json(json_data, bot)
+
+        assert isinstance(voice_chat_participants.users, list)
+        assert voice_chat_participants.users[0] == user1
+        assert voice_chat_participants.users[1] == user2
+        assert voice_chat_participants.users[0].id == user1.id
+        assert voice_chat_participants.users[1].id == user2.id
+
+    def test_to_dict(self, user1, user2):
+        voice_chat_participants = VoiceChatParticipantsInvited([user1, user2])
+        voice_chat_dict = voice_chat_participants.to_dict()
+
+        assert isinstance(voice_chat_dict, dict)
+        assert voice_chat_dict["users"] == [user1.to_dict(), user2.to_dict()]
+        assert voice_chat_dict["users"][0]["id"] == user1.id
+        assert voice_chat_dict["users"][1]["id"] == user2.id
+
+    def test_equality(self, user1, user2):
+        a = VoiceChatParticipantsInvited([user1])
+        b = VoiceChatParticipantsInvited([user1])
+        c = VoiceChatParticipantsInvited([user1, user2])
+        d = VoiceChatParticipantsInvited([user2])
+
+        assert a == b
+        assert hash(a) == hash(b)
+
+        assert a != c
+        assert hash(a) != hash(c)
+
+        assert a != d
+        assert hash(a) != hash(d)


Code review comments:
diff_hunk: @@ -3766,6 +3805,155 @@ def export_chat_invite_link(
 
         return result  # type: ignore[return-value]
 
+    @log
+    def create_chat_invite_link(
+        self,
+        chat_id: Union[str, int],
+        expire_date: Union[int, datetime] = None,
+        member_limit: int = None,
+        timeout: ODVInput[float] = DEFAULT_NONE,
+        api_kwargs: JSONDict = None,
+    ) -> ChatInviteLink:
+        """
+        Use this method to create an additional invite link for a chat. The bot must be an
+        administrator in the chat for this to work and must have the appropriate admin rights.
+        The link can be revoked using the method :attr:`revokeChatInviteLink`.
path: telegram/bot.py
text: @user1:
```suggestion
        The link can be revoked using the method :methd:`revoke_chat_invite_link`.
```

diff_hunk: @@ -0,0 +1,101 @@
+#!/usr/bin/env python
+#
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+"""This module contains an object that represents an invite link for a chat."""
+import datetime
+from typing import TYPE_CHECKING, Any, Optional
+
+from telegram import TelegramObject, User
+from telegram.utils.helpers import from_timestamp, to_timestamp
+from telegram.utils.types import JSONDict
+
+if TYPE_CHECKING:
+    from telegram import Bot
+
+
+class ChatInviteLink(TelegramObject):
+    """This object represents an invite link for a chat.
+
+    Objects of this class are comparable in terms of equality. Two objects of this class are
+    considered equal, if their :attr:`invite_link` and :attr:`creator` are equal.
path: telegram/chatinvitelink.py
text: @user1:
`is_primary` and `is_revoked` are missing

diff_hunk: @@ -1522,6 +1526,33 @@ def test_export_chat_invite_link(self, bot, channel_id):
         assert isinstance(invite_link, str)
         assert invite_link != ''
 
+    @flaky(3, 1)
+    @pytest.mark.timeout(10)
+    def test_advanced_chat_invite_links(self, bot, channel_id):
+        # we are testing this all in one function in order to save api calls
+        timestamp = dtm.datetime.utcnow()
+        add_seconds = dtm.timedelta(0, 70)
+        time_in_future = timestamp + add_seconds
+        invite_link = bot.create_chat_invite_link(
+            channel_id, expire_date=time_in_future, member_limit=10
+        )
+        assert invite_link.invite_link != ''
path: tests/test_bot.py
text: @user1:
also assert that it doesn't end with `'…'`?

diff_hunk: @@ -1453,6 +1473,13 @@ def test_filters_dice_type(self, update):
         assert not Filters.dice.darts(update)
         assert not Filters.dice.slot_machine([4])(update)
 
+        update.message.dice = Dice(5, '🎳')
+        assert Filters.dice.bowling(update)
+        assert Filters.dice.bowling([4, 5])(update)
+        assert not Filters.dice.dice(update)
+        assert not Filters.dice.darts(update)
+        assert not Filters.dice.football([4])(update)
path: tests/test_filters.py
text: @user1:
```suggestion
        assert not Filters.dice.bowling([4])(update)
```

diff_hunk: @@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# A library that provides a Python interface to the Telegram Bot API
+# Copyright (C) 2015-2021
+# Leandro Toledo de Souza <devs@python-telegram-bot.org>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Lesser Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser Public License for more details.
+#
+# You should have received a copy of the GNU Lesser Public License
+# along with this program.  If not, see [http://www.gnu.org/licenses/].
+
+import pytest
+
+from telegram import VoiceChatStarted, VoiceChatEnded, VoiceChatParticipantsInvited, User
+
+
+@pytest.fixture(scope='class')
+def user1():
+    return User(first_name='Misses Test', id=123, is_bot=False)
+
+
+@pytest.fixture(scope='class')
+def user2():
+    return User(first_name='Mister Test', id=124, is_bot=False)
+
+
+class TestVoiceChatStarted:
+    def test_de_json(self):
+        voice_chat_started = VoiceChatStarted.de_json({}, None)
+        assert isinstance(voice_chat_started, VoiceChatStarted)
+
+    def test_to_dict(self):
+        voice_chat_started = VoiceChatStarted()
+        voice_chat_dict = voice_chat_started.to_dict()
+        assert voice_chat_dict == {}
+
+
+class TestVoiceChatEnded:
+    duration = 100
+
+    def test_de_json(self):
+        json_dict = {'duration': self.duration}
+        voice_chat_ended = VoiceChatEnded.de_json(json_dict, None)
+
+        assert voice_chat_ended.duration == self.duration
+
+    def test_to_dict(self):
+        voice_chat_ended = VoiceChatEnded(self.duration)
+        voice_chat_dict = voice_chat_ended.to_dict()
+
+        assert isinstance(voice_chat_dict, dict)
+        assert voice_chat_dict["duration"] == self.duration
+
+    def test_equality(self):
+        a = VoiceChatEnded(100)
+        b = VoiceChatEnded(100)
+        c = VoiceChatEnded(50)
+        d = VoiceChatEnded(25)
path: tests/test_voicechat.py
text: @user1:
```suggestion
        d = VoiceChatStarted()
```