Skip to content
Merged
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#february-9-2026"><img src="https://img.shields.io/badge/Bot%20API-9.4-blue?logo=telegram" alt="Supported Bot API version"></a>
## <p align="center">Supported Bot API version: <a href="https://core.telegram.org/bots/api#march-1-2026"><img src="https://img.shields.io/badge/Bot%20API-9.5-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
12 changes: 12 additions & 0 deletions examples/asynchronous_telebot/chat_member_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,17 @@ async def my_chat_m(message: types.ChatMemberUpdated):
@bot.message_handler(content_types=util.content_type_service)
async def delall(message: types.Message):
await bot.delete_message(message.chat.id,message.message_id)


@bot.message_handler(commands=['set_tag'])
async def set_tag(message: types.Message):
tag = util.extract_arguments(message.text)
if not tag:
await bot.reply_to(message, "Usage: /set_tag your_tag")
return
await bot.set_chat_member_tag(message.chat.id, message.from_user.id, tag=tag)
await bot.reply_to(message, f"Tag updated: {tag}")


import asyncio
asyncio.run(bot.polling(allowed_updates=util.update_types))
21 changes: 19 additions & 2 deletions examples/asynchronous_telebot/formatting_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from telebot.async_telebot import AsyncTeleBot
from telebot import formatting
from telebot import formatting, types

bot = AsyncTeleBot('token')

Expand Down Expand Up @@ -50,5 +50,22 @@ async def start_message(message):
parse_mode='HTML'
)

# Bot API 9.5: date_time entity example
date_text = "2026-03-01 12:00:00"
text = f"Local time: {date_text}"
await bot.send_message(
message.chat.id,
text,
entities=[
types.MessageEntity(
type='date_time',
offset=len("Local time: "),
length=len(date_text),
unix_time=1772366400,
date_time_format='short'
)
]
)

import asyncio
asyncio.run(bot.polling())
asyncio.run(bot.polling())
22 changes: 22 additions & 0 deletions examples/asynchronous_telebot/send_message_draft_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import asyncio

from telebot.async_telebot import AsyncTeleBot

bot = AsyncTeleBot("TOKEN")


@bot.message_handler(commands=['draft'])
async def send_draft(message):
if message.chat.type != 'private':
await bot.reply_to(message, "This example works in private chats.")
return

draft_id = message.from_user.id
await bot.send_message_draft(message.chat.id, draft_id, "Generating response...")
await asyncio.sleep(1)
await bot.send_message_draft(message.chat.id, draft_id, "Still working...")
await asyncio.sleep(1)
await bot.send_message(message.chat.id, "Done.")


asyncio.run(bot.polling())
12 changes: 12 additions & 0 deletions examples/chat_member_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ def my_chat_m(message: types.ChatMemberUpdated):
@bot.message_handler(content_types=util.content_type_service)
def delall(message: types.Message):
bot.delete_message(message.chat.id,message.message_id)


@bot.message_handler(commands=['set_tag'])
def set_tag(message: types.Message):
tag = util.extract_arguments(message.text)
if not tag:
bot.reply_to(message, "Usage: /set_tag your_tag")
return
bot.set_chat_member_tag(message.chat.id, message.from_user.id, tag=tag)
bot.reply_to(message, f"Tag updated: {tag}")


bot.infinity_polling(allowed_updates=util.update_types)
21 changes: 19 additions & 2 deletions examples/formatting_example.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from telebot import TeleBot
from telebot import formatting
from telebot import formatting, types

bot = TeleBot('TOKEN')

Expand Down Expand Up @@ -50,4 +50,21 @@ def start_message(message):
parse_mode='HTML'
)

bot.infinity_polling()
# Bot API 9.5: date_time entity example
date_text = "2026-03-01 12:00:00"
text = f"Local time: {date_text}"
bot.send_message(
message.chat.id,
text,
entities=[
types.MessageEntity(
type='date_time',
offset=len("Local time: "),
length=len(date_text),
unix_time=1772366400,
date_time_format='short'
)
]
)

bot.infinity_polling()
22 changes: 22 additions & 0 deletions examples/send_message_draft_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import time

import telebot

bot = telebot.TeleBot("TOKEN")


@bot.message_handler(commands=['draft'])
def send_draft(message):
if message.chat.type != 'private':
bot.reply_to(message, "This example works in private chats.")
return

draft_id = message.from_user.id
bot.send_message_draft(message.chat.id, draft_id, "Generating response...")
time.sleep(1)
bot.send_message_draft(message.chat.id, draft_id, "Still working...")
time.sleep(1)
bot.send_message(message.chat.id, "Done.")


bot.infinity_polling()
33 changes: 31 additions & 2 deletions telebot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4237,7 +4237,7 @@ def send_message_draft(
entities: Optional[List[types.MessageEntity]]=None):
"""
Use this method to stream a partial message to a user while the message is being generated;
supported only for bots with forum topic mode enabled. Returns True on success.
available for all bots. Returns True on success.

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

Expand Down Expand Up @@ -4487,7 +4487,8 @@ def promote_chat_member(
can_post_stories: Optional[bool]=None,
can_edit_stories: Optional[bool]=None,
can_delete_stories: Optional[bool]=None,
can_manage_direct_messages: Optional[bool]=None) -> bool:
can_manage_direct_messages: Optional[bool]=None,
can_manage_tags: Optional[bool]=None) -> bool:
"""
Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator
in the chat for this to work and must have the appropriate admin rights.
Expand Down Expand Up @@ -4561,6 +4562,9 @@ def promote_chat_member(
within the channel and decline suggested posts; for channels only
:type can_manage_direct_messages: :obj:`bool`

:param can_manage_tags: Pass True if the administrator can manage tags in the chat
:type can_manage_tags: :obj:`bool`

:return: True on success.
:rtype: :obj:`bool`
"""
Expand All @@ -4578,6 +4582,7 @@ def promote_chat_member(
can_manage_video_chats=can_manage_video_chats, can_manage_topics=can_manage_topics,
can_post_stories=can_post_stories, can_edit_stories=can_edit_stories,
can_delete_stories=can_delete_stories, can_manage_direct_messages=can_manage_direct_messages,
can_manage_tags=can_manage_tags,
)


Expand Down Expand Up @@ -4606,6 +4611,30 @@ def set_chat_administrator_custom_title(
return apihelper.set_chat_administrator_custom_title(self.token, chat_id, user_id, custom_title)


def set_chat_member_tag(
self, chat_id: Union[int, str], user_id: int, tag: Optional[str]=None) -> bool:
"""
Use this method to set a new tag for a member in a chat.
Returns True on success.

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

:param chat_id: Unique identifier for the target chat or username of the target supergroup
(in the format @supergroupusername)
:type chat_id: :obj:`int` or :obj:`str`

:param user_id: Unique identifier of the target user
:type user_id: :obj:`int`

:param tag: New tag for the member; pass an empty string to remove the tag
:type tag: :obj:`str`

:return: True on success.
:rtype: :obj:`bool`
"""
return apihelper.set_chat_member_tag(self.token, chat_id, user_id, tag=tag)


def ban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel.
Expand Down
12 changes: 11 additions & 1 deletion telebot/apihelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,7 @@ def promote_chat_member(
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None,
can_manage_topics=None, can_post_stories=None, can_edit_stories=None,
can_delete_stories=None, can_manage_direct_messages=None):
can_delete_stories=None, can_manage_direct_messages=None, can_manage_tags=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
Expand Down Expand Up @@ -1322,6 +1322,8 @@ def promote_chat_member(
payload['can_delete_stories'] = can_delete_stories
if can_manage_direct_messages is not None:
payload['can_manage_direct_messages'] = can_manage_direct_messages
if can_manage_tags is not None:
payload['can_manage_tags'] = can_manage_tags
return _make_request(token, method_url, params=payload, method='post')


Expand All @@ -1333,6 +1335,14 @@ def set_chat_administrator_custom_title(token, chat_id, user_id, custom_title):
return _make_request(token, method_url, params=payload, method='post')


def set_chat_member_tag(token, chat_id, user_id, tag=None):
method_url = 'setChatMemberTag'
payload = {'chat_id': chat_id, 'user_id': user_id}
if tag is not None:
payload['tag'] = tag
return _make_request(token, method_url, params=payload, method='post')


def ban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'banChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
Expand Down
35 changes: 32 additions & 3 deletions telebot/async_telebot.py
Original file line number Diff line number Diff line change
Expand Up @@ -5757,7 +5757,7 @@ async def send_message_draft(
entities: Optional[List[types.MessageEntity]]=None):
"""
Use this method to stream a partial message to a user while the message is being generated;
supported only for bots with forum topic mode enabled. Returns True on success.
available for all bots. Returns True on success.

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

Expand Down Expand Up @@ -5996,7 +5996,8 @@ async def promote_chat_member(
can_post_stories: Optional[bool]=None,
can_edit_stories: Optional[bool]=None,
can_delete_stories: Optional[bool]=None,
can_manage_direct_messages: Optional[bool]=None) -> bool:
can_manage_direct_messages: Optional[bool]=None,
can_manage_tags: Optional[bool]=None) -> bool:
"""
Use this method to promote or demote a user in a supergroup or a channel. The bot must be an administrator
in the chat for this to work and must have the appropriate admin rights.
Expand Down Expand Up @@ -6070,6 +6071,9 @@ async def promote_chat_member(
within the channel and decline suggested posts; for channels only
:type can_manage_direct_messages: :obj:`bool`

:param can_manage_tags: Pass True if the administrator can manage tags in the chat
:type can_manage_tags: :obj:`bool`

:return: True on success.
:rtype: :obj:`bool`
"""
Expand All @@ -6084,7 +6088,8 @@ async def promote_chat_member(
can_edit_messages, can_delete_messages, can_invite_users,
can_restrict_members, can_pin_messages, can_promote_members,
is_anonymous, can_manage_chat, can_manage_video_chats, can_manage_topics,
can_post_stories, can_edit_stories, can_delete_stories, can_manage_direct_messages=can_manage_direct_messages
can_post_stories, can_edit_stories, can_delete_stories,
can_manage_direct_messages=can_manage_direct_messages, can_manage_tags=can_manage_tags
)

async def set_chat_administrator_custom_title(
Expand Down Expand Up @@ -6112,6 +6117,30 @@ async def set_chat_administrator_custom_title(
return await asyncio_helper.set_chat_administrator_custom_title(self.token, chat_id, user_id, custom_title)


async def set_chat_member_tag(
self, chat_id: Union[int, str], user_id: int, tag: Optional[str]=None) -> bool:
"""
Use this method to set a new tag for a member in a chat.
Returns True on success.

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

:param chat_id: Unique identifier for the target chat or username of the target supergroup
(in the format @supergroupusername)
:type chat_id: :obj:`int` or :obj:`str`

:param user_id: Unique identifier of the target user
:type user_id: :obj:`int`

:param tag: New tag for the member; pass an empty string to remove the tag
:type tag: :obj:`str`

:return: True on success.
:rtype: :obj:`bool`
"""
return await asyncio_helper.set_chat_member_tag(self.token, chat_id, user_id, tag=tag)


async def ban_chat_sender_chat(self, chat_id: Union[int, str], sender_chat_id: Union[int, str]) -> bool:
"""
Use this method to ban a channel chat in a supergroup or a channel.
Expand Down
12 changes: 11 additions & 1 deletion telebot/asyncio_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -1281,7 +1281,7 @@ async def promote_chat_member(
can_restrict_members=None, can_pin_messages=None, can_promote_members=None,
is_anonymous=None, can_manage_chat=None, can_manage_video_chats=None, can_manage_topics=None,
can_post_stories=None, can_edit_stories=None, can_delete_stories=None,
can_manage_direct_messages=None):
can_manage_direct_messages=None, can_manage_tags=None):
method_url = 'promoteChatMember'
payload = {'chat_id': chat_id, 'user_id': user_id}
if can_change_info is not None:
Expand Down Expand Up @@ -1316,6 +1316,8 @@ async def promote_chat_member(
payload['can_delete_stories'] = can_delete_stories
if can_manage_direct_messages is not None:
payload['can_manage_direct_messages'] = can_manage_direct_messages
if can_manage_tags is not None:
payload['can_manage_tags'] = can_manage_tags
return await _process_request(token, method_url, params=payload, method='post')


Expand All @@ -1327,6 +1329,14 @@ async def set_chat_administrator_custom_title(token, chat_id, user_id, custom_ti
return await _process_request(token, method_url, params=payload, method='post')


async def set_chat_member_tag(token, chat_id, user_id, tag=None):
method_url = 'setChatMemberTag'
payload = {'chat_id': chat_id, 'user_id': user_id}
if tag is not None:
payload['tag'] = tag
return await _process_request(token, method_url, params=payload, method='post')


async def ban_chat_sender_chat(token, chat_id, sender_chat_id):
method_url = 'banChatSenderChat'
payload = {'chat_id': chat_id, 'sender_chat_id': sender_chat_id}
Expand Down
Loading