Как опубликовать историю Telegram через API
История в Telegram публикуется только от имени аккаунта — методом MTProto stories.sendStory; в Bot API такого метода нет вовсе. Перед публикацией вызывается stories.canSendStory: от имени пользователя нужен Premium, от имени канала — право post_stories и достаточное число бустов. Медиа должно быть вертикальным фото или видео не больше 30 МБ.
Обновлено:
Как опубликовать историю через Telegram API?
Три шага. Сначала stories.canSendStory проверяет право — в ответе приходит число свободных «слотов» под истории. Затем stories.sendStory получает вертикальное фото или видео (до 30 МБ), правила приватности и необязательный period. В ответе внутри updateStoryID возвращается id новой истории — он нужен для редактирования и удаления.
Всё это живёт на уровне MTProto, то есть в сессии аккаунта. В Socialift это клиент TelegramAccount; он работает поверх Telethon и ставится через pip install "socialift[telegram]".
Историю можно опубликовать и от имени канала или супергруппы, но тогда вы должны быть админом с правом post_stories.
Bot API и MTProto: разница по историям
Это первый и самый дорогой по времени вопрос. С токеном бота истории не публикуются, и это не временное ограничение.
| Действие | Bot API | MTProto (аккаунт) |
|---|---|---|
| Публикация истории | нет — метода не существует | stories.sendStory |
| Увидеть входящую историю | да — история приходит сообщением | да |
| Ответить на историю | да | да |
| Редактирование истории | нет | stories.editStory |
| Удаление истории | нет | stories.deleteStories |
| Список активных историй | нет | stories.getPeerStories |
Бот только получает историю и может на неё ответить. Поэтому в Socialift методы историй не дублируются в клиенте Telegram (бот) — они есть только в TelegramAccount.
Почему бот не может публиковать истории
История — элемент профиля пользователя. Telegram сделал её для аккаунтов и каналов, а не для ботов: в документации Bot API нет метода отправки истории, есть только объект входящей истории и ответ на неё.
На практике это значит: если в контент-плане есть истории, проекту понадобится сессия аккаунта — с api_id и api_hash, по номеру телефона. Это более серьёзное решение, чем бот: файл сессии нужно хранить зашифрованным и соблюдать ограничения платформы.
Связка из двух клиентов в одном проекте — обычная практика: посты и сообщения через бота, истории — через аккаунт.
Сначала проверка: can_send_story
Документация Telegram требует именно этого: «Before posting a story, clients should invoke stories.canSendStory». Ошибку видно до загрузки файла, а не после.
import asyncio
from socialift import ApiError, TelegramAccount
async def main():
async with TelegramAccount.from_env() as tg:
targets = await tg.story_targets()
print("можно от имени канала:", targets.chats)
try:
check = await tg.can_send_story("me")
except ApiError as exc:
print("сейчас опубликовать нельзя:", exc)
return
print("свободных слотов:", check.count)
asyncio.run(main())При успехе can_send_story() возвращает stories.CanSendStoryCount: count — число свободных слотов, то есть лимит минус текущие активные истории.
story_targets() (stories.getChatsToSend) перечисляет каналы и супергруппы, от имени которых можно публиковать. Попадание в список ещё не значит «можно» — бусты и лимиты всё равно проверяются в can_send_story().
Проверка не даёт гарантии: если между can_send_story() и send_story() состояние изменится (например, история опубликована с другого устройства), та же ошибка вернётся уже из send_story().
Кто может публиковать и какие ошибки приходят
Если условия не выполнены, Telegram возвращает конкретный код ошибки — SDK переводит их в свои типы исключений.
| Ситуация | Ошибка Telegram | Что делать |
|---|---|---|
| У пользователя нет Premium | PREMIUM_ACCOUNT_REQUIRED | Личные истории только с Premium; рассмотрите публикацию от имени канала |
| Нет права post_stories в канале | CHAT_ADMIN_REQUIRED | Выдайте админку и именно это право (в SDK — PermissionError) |
| Каналу не хватает бустов | BOOSTS_REQUIRED | Дождитесь нужного числа бустов |
| Лимит активных историй | STORIES_TOO_MUCH | Дождитесь истечения старых или удалите их |
| Недельный/месячный лимит | STORY_SEND_FLOOD_WEEKLY_%d или _MONTHLY_%d | Секунды ожидания приходят в RateLimitError.retry_after |
Длительность: значения period
Telegram принимает ровно четыре значения period, остальные отклоняет сервер. Socialift SDK проверяет это до загрузки файла.
| Длительность | period (секунды) | Для кого |
|---|---|---|
| 6 часов | 21600 | только Premium |
| 12 часов | 43200 | только Premium |
| 24 часа | 86400 | по умолчанию, для всех |
| 48 часов | 172800 | только Premium |
Если period не передан, поле не отправляется и Telegram ставит 24 часа. По истечении срока история уходит в архив; при pinned=True она остаётся и в профиле.
Приватность: кто увидит историю
В MTProto это Vector<InputPrivacyRule>. SDK сводит его к четырём сокращениям, а для сложных случаев принимает готовый список правил.
- everyone
- Значение по умолчанию, как в приложении —
InputPrivacyValueAllowAll. Историю видят все. - contacts
- Только контакты —
InputPrivacyValueAllowContacts. - close_friends
- Только «близкие друзья» —
InputPrivacyValueAllowCloseFriends. Сам список управляется черезcontacts.editCloseFriends. - selected
- Только выбранные пользователи —
InputPrivacyValueAllowUsers. При этом значении списокallowобязателен. - deny
- Исключения —
InputPrivacyValueDisallowUsers. Правила применяются в переданном порядке, поэтомуdenyдобавляется последним: «контакты, но не вот эти».
Медиа и текст: вертикаль, 30 МБ и ловушка подписи
Документация Telegram описывает медиа коротко: вертикальное фото или вертикальное видео, максимум 30 МБ. Цифр по соотношению сторон и длительности в документации нет, поэтому SDK их и не проверяет — невертикальное медиа обрежется в приложениях неправильно, но без ошибки.
Ограничение по размеру SDK проверяет локально: если передан путь к файлу или байты, файл больше 30 МБ не поедет на сервер впустую — сразу поднимается ConfigurationError.
caption — текст под историей. Его предельная длина приходит из серверной конфигурации (story_caption_length_limit_*) и цифрой в документации не зафиксирована. Форматирование (entities) зависит от конфигурации stories_entities: то есть не у всех аккаунтов в тексте истории работают жирный шрифт и ссылки. Без parse_mode текст уходит без разметки.
noforwards=True запрещает пересылку и сохранение истории — на случай, когда контент не должен расходиться дальше.
Публикация истории через Socialift SDK
send_story загружает файл, собирает правила приватности и вызывает stories.sendStory. Ответ — Updates, внутри id новой истории.
import asyncio
from socialift import RateLimitError, TelegramAccount
async def main():
async with TelegramAccount.from_env() as tg:
check = await tg.can_send_story("me")
if not check.count:
print("лимит активных историй исчерпан")
return
try:
result = await tg.send_story(
"me",
"story.mp4",
caption="Новая коллекция",
period=43200,
privacy="close_friends",
deny=["@konkurent"],
pinned=True,
noforwards=True,
)
except RateLimitError as exc:
print("недельный или месячный лимит, ждать:", exc.retry_after)
return
print(result)
asyncio.run(main())TelegramAccount.from_env() читает TELEGRAM_API_ID, TELEGRAM_API_HASH и TELEGRAM_SESSION. Токен бота здесь не подойдёт.
file — путь, байты, файловый объект или готовый InputFile. Тип определяется по расширению (.jpg и .png — фото, остальное — видео); принудительно — photo=True или photo=False.
Чтобы опубликовать от имени канала, передайте его первым аргументом: send_story("@my_channel", ...). Тогда проверяется не Premium, а право post_stories и бусты.
period=43200 (12 часов) на аккаунте без Premium будет отклонён — если не уверены, не передавайте period, и Telegram поставит 24 часа.
Чтение, редактирование и удаление
При редактировании отправляются только переданные поля, остальные не меняются — поэтому в edit_story у privacy значение по умолчанию None.
import asyncio
from socialift import TelegramAccount
async def main():
async with TelegramAccount.from_env() as tg:
peer = await tg.stories("me")
for story in peer.stories:
print(story.id, story.expire_date)
await tg.edit_story("me", 42, caption="Исправленный текст")
await tg.edit_story("me", 42, privacy="contacts", deny=["@konkurent"])
await tg.delete_story("me", [42, 43])
asyncio.run(main())stories(entity) отдаёт только СЕЙЧАС активные истории (stories.getPeerStories). Иногда в ответе приходят одни id — их запрашивают отдельно: stories(entity, ids=[...]).
Истёкших историй в этом списке нет: они в архиве (stories.getStoriesArchive) или в профиле (stories.getPinnedStories) — для них используйте raw().
Если в edit_story не передать ничего, будет ConfigurationError: пустое редактирование — бессмысленный запрос. При замене file медиа перезаливается целиком, потому что по документации DocumentAttribute намертво привязаны к медиа.
delete_story необратимо: удаляются и активная, и закреплённая в профиле, и архивная история.
Чек-лист перед запуском
- Не пытаетесь ли вы публиковать историю токеном бота — такого метода в Bot API нет.
- Перед каждой публикацией вызывайте can_send_story() и проверяйте count.
- Медиа вертикальное и меньше 30 МБ; соотношение сторон контролируйте сами — Telegram его не зафиксировал.
- В period передавайте только 21600, 43200, 86400 или 172800; без Premium — только 86400.
- При privacy="selected" список allow обязателен.
- Ошибки STORY_SEND_FLOOD_WEEKLY и MONTHLY ловите как RateLimitError и ждите retry_after.
- Для публикации от имени канала заранее проверяйте право post_stories и бусты.
- Файл сессии храните зашифрованным — он даёт полный доступ к аккаунту.
- Форматирование в тексте истории зависит от серверной настройки stories_entities и работает не у всех.
Частые вопросы
Может ли Telegram-бот публиковать истории?
Нет. В Bot API нет метода публикации истории — бот только видит входящую историю и может на неё ответить. Для публикации нужны MTProto и сессия аккаунта: в Socialift это клиент TelegramAccount.
Нужен ли Telegram Premium для публикации истории?
От имени пользователя — да, иначе придёт PREMIUM_ACCOUNT_REQUIRED. От имени канала или супергруппы Premium не нужен, но требуются админское право post_stories и достаточное число бустов у канала.
Сколько живёт история и можно ли это изменить?
Параметр period принимает четыре значения: 21600 (6 часов), 43200 (12), 86400 (24) и 172800 (48). На аккаунте без Premium работает только 86400. Если не передать, Telegram поставит 24 часа; после этого история уходит в архив, а при pinned=True остаётся и в профиле.
Какие ограничения у медиа для истории?
Вертикальное фото или вертикальное видео, максимум 30 МБ. Точных цифр по соотношению сторон и длительности в документации Telegram нет, поэтому невертикальное медиа опубликуется без ошибки, но обрежется неправильно.
Можно ли отредактировать опубликованную историю?
Да, через stories.editStory: текст, приватность, медиа и media_areas. Меняются только переданные поля. При замене медиа файл загружается заново, так как по документации DocumentAttribute привязаны к самому медиа.
Как ограничить круг зрителей истории?
Значения privacy: everyone, contacts, close_friends и selected (в последнем случае список allow обязателен). Чтобы исключить отдельных людей, используйте deny — он добавляется последним правилом.