Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
<p align="center">A simple, but extensible Python implementation for the <a href="https://core.telegram.org/bots/api">Telegram Bot API</a>.</p>
<p align="center">Both synchronous and asynchronous.</p>

## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#may-8-2026"><img src="https://img.shields.io/badge/Bot%20API-10.0-blue?logo=telegram" alt="Supported Bot API version"></a>
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#june-11-2026"><img src="https://img.shields.io/badge/Bot%20API-10.1-blue?logo=telegram" alt="Supported Bot API version"></a>

<h2><a href='https://pytba.readthedocs.io/en/latest/index.html'>Official documentation</a></h2>
<h2><a href='https://pytba.readthedocs.io/ru/latest/index.html'>Official ru documentation</a></h2>
Expand Down
142 changes: 140 additions & 2 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4453,7 +4453,105 @@ def send_message_draft(
"""
return apihelper.send_message_draft(
self.token, chat_id, draft_id, text, parse_mode=parse_mode, entities=entities, message_thread_id=message_thread_id)

def send_rich_message(
self, chat_id: Union[int, str],
rich_message: types.InputRichMessage,
business_connection_id: Optional[str]=None,
message_thread_id: Optional[int]=None,
direct_messages_topic_id: Optional[int]=None,
disable_notification: Optional[bool]=None,
protect_content: Optional[bool]=None,
allow_paid_broadcast: Optional[bool]=None,
message_effect_id: Optional[str]=None,
suggested_post_parameters: Optional[types.SuggestedPostParameters]=None,
reply_parameters: Optional[types.ReplyParameters]=None,
reply_markup: Optional[REPLY_MARKUP_TYPES]=None) -> types.Message:
"""
Use this method to send rich messages. If the message contains a block with a media element,
then the bot must have the right to send the media to the chat. On success, the sent Message is returned.

Telegram documentation: https://core.telegram.org/bots/api#sendrichmessage

:param chat_id: Unique identifier for the target chat or username of the target bot, supergroup or channel in the format @username
:type chat_id: :obj:`int` or :obj:`str`

:param rich_message: The message to be sent
:type rich_message: :class:`telebot.types.InputRichMessage`

:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
:type disable_notification: :obj:`bool`

:param protect_content: Protects the contents of the sent message from forwarding and saving
:type protect_content: :obj:`bool`

:param allow_paid_broadcast: Pass True to allow up to 1000 messages per second, ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance.
:type allow_paid_broadcast: :obj:`bool`

:param message_effect_id: Unique identifier of the message effect to be added to the message; for private chats only
:type message_effect_id: :obj:`str`

:param suggested_post_parameters: A JSON-serialized object containing the parameters of the suggested post to send;
for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined.
:type suggested_post_parameters: :class:`telebot.types.SuggestedPostParameters`

:param reply_parameters: Description of the message to reply to
:type reply_parameters: :class:`telebot.types.ReplyParameters`

:param reply_markup: Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user.
:type reply_markup: :class:`telebot.types.InlineKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardMarkup` or :class:`telebot.types.ReplyKeyboardRemove` or :class:`telebot.types.ForceReply`

:param business_connection_id: Identifier of a business connection
:type business_connection_id: :obj:`str`

:param message_thread_id: The thread identifier of a message from which the reply will be sent
:type message_thread_id: :obj:`int`

:param direct_messages_topic_id: Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat
:type direct_messages_topic_id: :obj:`int`

:return: On success, the sent Message is returned.
:rtype: :class:`telebot.types.Message`
"""
disable_notification = self.disable_notification if (disable_notification is None) else disable_notification
protect_content = self.protect_content if (protect_content is None) else protect_content

return types.Message.de_json(
apihelper.send_rich_message(
self.token, chat_id, rich_message, disable_notification=disable_notification, protect_content=protect_content,
allow_paid_broadcast=allow_paid_broadcast, message_effect_id=message_effect_id, suggested_post_parameters=suggested_post_parameters, reply_parameters=reply_parameters,
reply_markup=reply_markup, business_connection_id=business_connection_id, message_thread_id=message_thread_id, direct_messages_topic_id=direct_messages_topic_id)
)

def send_rich_message_draft(
self, chat_id: int,
draft_id: int,
rich_message: types.InputRichMessage,
message_thread_id: Optional[int]=None) -> bool:
"""
Use this method to stream a partial rich message to a user while the message is being generated
Note that the streamed draft is ephemeral and acts as a temporary 30-second preview - once the output
is finalized, you must call sendRichMessage with the complete message to persist it in the user's chat. Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#sendrichmessagedraft

:param chat_id: Unique identifier for the target private chat
:type chat_id: :obj:`int`

:param draft_id: Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated.
:type draft_id: :obj:`int`

:param rich_message: The partial message to be streamed
:type rich_message: :class:`telebot.types.InputRichMessage`

:param message_thread_id: Unique identifier for the target message thread
:type message_thread_id: :obj:`int`

:return: Returns True on success.
:rtype: :obj:`bool`
"""
return apihelper.send_rich_message_draft(
self.token, chat_id, draft_id, rich_message, message_thread_id=message_thread_id)


def send_chat_action(
Expand Down Expand Up @@ -5114,6 +5212,42 @@ def decline_chat_join_request(self, chat_id: Union[str, int], user_id: Union[int
"""
return apihelper.decline_chat_join_request(self.token, chat_id, user_id)

def answer_chat_join_request_query(self, chat_join_request_query_id: str, result: str) -> bool:
"""
Use this method to process a received chat join request query. Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#answerchatjoinrequestquery

:param chat_join_request_query_id: Unique identifier of the join request query
:type chat_join_request_query_id: :obj:`str`

:param result: Result of the query. Must be either “approve” to allow the user to join the chat,
“decline” to disallow the user to join the chat, or “queue” to leave the decision to other administrators.
:type result: :obj:`str`

:return: True on success.
:rtype: :obj:`bool`
"""
return apihelper.answer_chat_join_request_query(self.token, chat_join_request_query_id, result)

def send_chat_join_request_web_app(self, chat_join_request_query_id: str, web_app_url: str) -> bool:
"""
Use this method to process a received chat join request query by showing a Mini App to the
user before deciding the outcome. Call answerChatJoinRequestQuery to resolve the join request query based on the user interaction with the Mini App.
Returns True on success.

Telegram documentation: https://core.telegram.org/bots/api#sendchatjoinrequestwebapp

:param chat_join_request_query_id: Unique identifier of the join request query
:type chat_join_request_query_id: :obj:`str`

:param web_app_url: The URL of the Mini App to be opened
:type web_app_url: :obj:`str`

:return: True on success.
:rtype: :obj:`bool`
"""
return apihelper.send_chat_join_request_web_app(self.token, chat_join_request_query_id, web_app_url)

def set_chat_photo(self, chat_id: Union[int, str], photo: Any) -> bool:
"""
Expand Down Expand Up @@ -5659,7 +5793,8 @@ def edit_message_text(
reply_markup: Optional[types.InlineKeyboardMarkup]=None,
link_preview_options : Optional[types.LinkPreviewOptions]=None,
business_connection_id: Optional[str]=None,
timeout: Optional[int]=None) -> Union[types.Message, bool]:
timeout: Optional[int]=None,
rich_message: Optional[types.InputRichMessage]=None) -> Union[types.Message, bool]:
"""
Use this method to edit text and game messages.

Expand Down Expand Up @@ -5698,6 +5833,9 @@ def edit_message_text(
:param timeout: Timeout in seconds for the request.
:type timeout: :obj:`int`

:param rich_message: New rich content of the message; required if text isn't specified
:type rich_message: :obj:`types.InputRichMessage`

:return: On success, if edited message is sent by the bot, the edited Message is returned, otherwise True is returned.
:rtype: :obj:`types.Message` or :obj:`bool`
"""
Expand Down Expand Up @@ -5725,7 +5863,7 @@ def edit_message_text(
result = apihelper.edit_message_text(
self.token, text, chat_id=chat_id, message_id=message_id, inline_message_id=inline_message_id,
parse_mode=parse_mode, entities=entities, reply_markup=reply_markup, link_preview_options=link_preview_options,
business_connection_id=business_connection_id, timeout=timeout)
business_connection_id=business_connection_id, timeout=timeout, rich_message=rich_message)

if isinstance(result, bool): # if edit inline message return is bool not Message.
return result
Expand Down
57 changes: 56 additions & 1 deletion telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,41 @@ def send_message(
return _make_request(token, method_url, params=payload, method='post')


def send_rich_message(
token, chat_id, rich_message,
disable_notification=None, protect_content=None, message_effect_id=None,
reply_parameters=None, reply_markup=None, business_connection_id=None,
direct_messages_topic_id=None, suggested_post_parameters=None, allow_paid_broadcast=None):
method_url = r'sendRichMessage'
payload = {'chat_id': str(chat_id), 'rich_message': rich_message.to_json()}
if disable_notification is not None:
payload['disable_notification'] = disable_notification
if protect_content is not None:
payload['protect_content'] = protect_content
if message_effect_id:
payload['message_effect_id'] = message_effect_id
if reply_parameters:
payload['reply_parameters'] = reply_parameters.to_json()
if reply_markup:
payload['reply_markup'] = _convert_markup(reply_markup)
if business_connection_id:
payload['business_connection_id'] = business_connection_id
if direct_messages_topic_id is not None:
payload['direct_messages_topic_id'] = direct_messages_topic_id
if suggested_post_parameters is not None:
payload['suggested_post_parameters'] = suggested_post_parameters.to_json()
if allow_paid_broadcast is not None:
payload['allow_paid_broadcast'] = allow_paid_broadcast
return _make_request(token, method_url, params=payload, method='post')

def send_rich_message_draft(token, chat_id, draft_id, rich_message, message_thread_id=None):
method_url = r'sendRichMessageDraft'
payload = {'chat_id': str(chat_id), 'draft_id': draft_id, 'rich_message': rich_message.to_json()}
if message_thread_id is not None:
payload['message_thread_id'] = message_thread_id
return _make_request(token, method_url, params=payload, method='post')


def set_webhook(token, url=None, certificate=None, max_connections=None, allowed_updates=None, ip_address=None,
drop_pending_updates = None, timeout=None, secret_token=None):
method_url = r'setWebhook'
Expand Down Expand Up @@ -1516,6 +1551,24 @@ def decline_chat_join_request(token, chat_id, user_id):
return _make_request(token, method_url, params=payload, method='post')


def answer_chat_join_request_query(token, chat_join_request_query_id, result):
method_url = 'answerChatJoinRequestQuery'
payload = {
'chat_join_request_query_id': chat_join_request_query_id,
'result': result
}
return _make_request(token, method_url, params=payload, method='post')


def send_chat_join_request_web_app(token, chat_join_request_query_id, web_app_url):
method_url = 'sendChatJoinRequestWebApp'
payload = {
'chat_join_request_query_id': chat_join_request_query_id,
'web_app_url': web_app_url
}
return _make_request(token, method_url, params=payload, method='post')


def set_chat_photo(token, chat_id, photo):
method_url = 'setChatPhoto'
payload = {'chat_id': chat_id}
Expand Down Expand Up @@ -1737,7 +1790,7 @@ def unpin_all_chat_messages(token, chat_id):

def edit_message_text(
token, text, chat_id=None, message_id=None, inline_message_id=None, parse_mode=None, entities = None,
reply_markup=None, link_preview_options=None, business_connection_id=None, timeout=None):
reply_markup=None, link_preview_options=None, business_connection_id=None, timeout=None, rich_message=None):
method_url = r'editMessageText'
payload = {'text': text}
if chat_id:
Expand All @@ -1758,6 +1811,8 @@ def edit_message_text(
payload['business_connection_id'] = business_connection_id
if timeout:
payload['timeout'] = timeout
if rich_message:
payload['rich_message'] = rich_message.to_json()
return _make_request(token, method_url, params=payload, method='post')


Expand Down
Loading
Loading