Перейти к основному содержимому

Фильтр сообщений

Обычные интеграции срабатывают после события: респондент прошёл опрос — ушло уведомление, добавилась строка в таблицу. Фильтр устроен иначе: он стоит до обработки. Мы отправляем вам сообщение, которое написал участник, берём ваш ответ и дальше работаем уже с ним.

Так можно:

  • обезличить текст до того, как он попадёт в нашу базу — вырезать телефоны, имена, номера договоров;
  • подменить команду — например, превратить «хочу отпуск» в переход к нужному опросу;
  • дописать своё поле для внутренней аналитики.

Чего фильтр не может — заблокировать сообщение. Он возвращает данные, а не решение: бот в любом случае продолжит работу.

Как это выглядит по времени

Пока ваш сервис думает, участник смотрит на неотвеченного бота. Поэтому:

ОграничениеЗначениеПочему так
Таймаут одного фильтра800 мсМедленный фильтр вредит прежде всего себе
Бюджет всей цепочки1,5 сТри фильтра по секунде дали бы три секунды задержки
Фильтров на событиене больше 5Цепочку из шести преобразований невозможно отладить

Не ответили вовремя — сообщение идёт дальше как есть. Бот не встанет и ошибку участнику не покажет.

Что мы присылаем

POST с телом — это апдейт Telegram в том виде, в каком его получил бот. Заголовки:

Content-Type: application/json
X-Pollagram-Signature: sha256=<HMAC тела запроса>
X-Pollagram-Timestamp: <миллисекунды>

Подпись считается тем секретом, который вы задали в настройках интеграции. Проверяйте её: без проверки любой, кто узнал ваш адрес, сможет присылать вам что угодно. Метка времени — против повторной отправки перехваченного запроса, отвергайте всё старше нескольких минут.

Тело — обычный апдейт Telegram, мы ничего в нём не меняем и не добавляем:

{
"update_id": 802341122,
"message": {
"message_id": 4711,
"from": {
"id": 123456789,
"is_bot": false,
"first_name": "Иван",
"username": "ivan",
"language_code": "ru"
},
"chat": {
"id": 123456789,
"first_name": "Иван",
"username": "ivan",
"type": "private"
},
"date": 1755471975,
"text": "Мой телефон +7 900 123-45-67"
}
}

Поэтому разбирать его можно любой готовой библиотекой для Bot API — структура ровно та же, что у вебхука Telegram.

Что вернуть

Либо изменённый апдейт целиком, либо пустое тело, если менять нечего. Пустой ответ — законный и самый дешёвый способ сказать «пропускай как есть».

Пример на Python:

@app.post("/telegram/filter")
def filter_update(update: dict):
text = update.get("message", {}).get("text", "")
if not text:
return {} # менять нечего

update["message"]["text"] = mask_phones(text)
return update

Любой ответ, кроме 2xx, считается отказом — сообщение пойдёт неизменённым.

Если ваш сервис лёг

Пять отказов подряд — и фильтр отключается на полминуты. Бот всё это время работает без него, а в кабинете у владельца появляется уведомление «Фильтр временно отключён». Когда сервис отвечает снова, фильтр включается сам и уведомление закрывается.

Это сделано не ради экономии: без такой паузы мы продолжали бы стучаться в лежащий сервис на каждое сообщение каждого участника — и мешали бы ему подняться.

Требования к адресу

  • только https (или http для адресов вне внутренних сетей);
  • адрес должен быть доступен из интернета;
  • локальные и служебные адреса (localhost, 192.168.*, 169.254.169.254) отклоняются при сохранении — с нашего сервера они вели бы во внутреннюю сеть.

Как подключить: по шагам

  1. Поднимите обработчик, который принимает POST с телом — это апдейт Telegram как есть, без изменений с нашей стороны.
  2. Верните изменённый апдейт целиком — или пустое тело, если менять нечего. Частичный ответ не принимается: мы не угадываем, что вы хотели заменить, а что оставить.
  3. Уложитесь в 800 мс. Не успели — бот отправит исходное сообщение, без ваших правок. Это осознанный выбор: молчащий бот хуже, чем бот без фильтра.
  4. В карточке «Фильтр апдейтов» вставьте адрес и включите интеграцию.

Как проверить, что фильтр работает

Проще всего — вернуть заведомо изменённый текст (например, добавить префикс) и написать боту. Если префикс появился, цепочка работает.

Если нет:

Что видноЧто это значит
Сообщение без измененийФильтр не ответил вовремя или вернул пустое тело
В журнале «превышен бюджет»Обработчик отвечает медленнее 800 мс
«Фильтр отключён после серии ошибок»Сработал предохранитель — см. ниже

Предохранитель

Если фильтр подряд отвечает ошибками, мы перестаём его звать на некоторое время и показываем уведомление в кабинете. Это защита бота: неотвечающий фильтр на каждом сообщении означал бы, что бот тормозит у всех респондентов.

Как только обработчик начинает отвечать штатно, вызовы возобновляются сами — включать ничего не нужно.