Когда Telegram-бот передаёт событие в CRM или другой рабочий сервис, получателю нужен понятный контракт данных. Недостаточно отправить произвольный JSON и договориться, что «там будет сообщение». Через несколько обновлений появятся новые поля, старые значения изменят смысл, а два разработчика начнут по-разному трактовать одно событие.
Контракт описывает, что произошло, к какому объекту это относится и как получатель должен обрабатывать повтор или неизвестную версию. Ниже рассматривается собственная интеграция между вашими сервисами. Её формат не следует путать с Telegram Bot API Update или документированными вебхуками конкретного продукта, включая Deskgram.
От события Telegram к событию приложения
Telegram присылает техническое обновление в своём формате. Приложение может на его основе создать внутреннее событие: принято обращение, подтверждена анкета или изменён статус. Эти сущности различаются. Один пользовательский сценарий иногда включает несколько обновлений, а одно обновление не всегда требует внешнего бизнес-события.
Назовите границу преобразования. Где проверяется вход, где определяется принадлежность обращению и когда событие считается созданным? Если каждый получатель самостоятельно разбирает сырой Telegram-объект, изменения платформы и контекста придётся учитывать во множестве мест. Собственный контракт может упростить связь, но требует сопровождения.
Не копируйте в него все входящие данные без необходимости. Получателю часто нужны идентификатор обращения, тип изменения и необходимые поля. Полный профиль пользователя и вся история чата увеличивают связанность сервисов и объём данных, которые приходится хранить и защищать отдельно.
Обязательные смысловые поля
У события полезно иметь уникальный идентификатор, тип, источник, время возникновения и версию схемы. Данные объекта размещают отдельно от технического конверта. Это проектная рекомендация, а не обязательный формат любого webhook. Если выбираете стандарт вроде CloudEvents, соблюдайте его определения и правила, а не используйте название для произвольной структуры.
Различайте идентификатор события и объекта. Обращение может иметь много событий, и каждое должно быть распознаваемым при повторной доставке. Если использовать номер обращения как единственный ключ события, получатель примет следующее законное изменение за повтор предыдущего.
Также полезна связь с цепочкой операции. Событие подтверждения анкеты может породить создание CRM-карточки и уведомление оператору. Идентификатор корреляции помогает восстановить этот путь, но не заменяет отдельные идентификаторы каждого изменения. Семантика полей должна быть записана словами, а не подразумеваться по имени.
Тип и версия
Тип сообщает, что произошло, а не какую функцию получатель обязан вызвать. Например, факт подтверждения заявки отличается от команды «создай запись». Смешение события и распоряжения затрудняет добавление новых получателей: один факт может быть полезен нескольким системам с разными действиями.
Версия нужна для изменений структуры и смысла. Добавление необязательного поля может быть совместимым, а переименование обязательного или изменение единицы измерения — нет. Правило совместимости определяют заранее. Не рассчитывайте, что все получатели обновятся одновременно в момент выпуска отправителя.
Получатель должен иметь определённое поведение для неизвестного типа и неподдерживаемой версии. Это может быть отдельная очередь разбора или отказ с диагностикой. Молчаливое принятие и игнорирование опасно, если отправитель считает событие успешно обработанным и больше к нему не вернётся.
Условный пример: подтверждение анкеты
Предположим, бот собирает заявку на консультацию. После финального подтверждения приложение создаёт собственное событие с идентификатором, типом, версией и ссылкой на подтверждённую анкету. В данных передаются только поля, необходимые CRM для создания обращения. Связь пользователя уже проверена предусмотренным процессом.
Позже команда добавляет необязательное пожелание по времени. Получатель старой версии продолжает работать, если согласованное правило допускает дополнительные поля. Но если меняется смысл даты или обязательность контакта, выпускается явное изменение контракта и проверяется переход между версиями.
Это условный пример, а не готовый payload Telegram или Deskgram. Реальные поля вебхуков конкретного продукта берут из его документации. Создавать у себя нормализованное событие допустимо, но нельзя подписывать вымышленную схему именем чужого API и ожидать совместимости.
Снимок данных или ссылка
В событие можно включить нужный снимок либо ссылку на актуальный объект. У обоих вариантов есть последствия. Снимок объясняет состояние в момент события, но дублирует данные. Ссылка уменьшает объём, однако получатель должен иметь доступ и понимать, что объект мог измениться до чтения.
Выберите подход по задаче и опишите его. Для воспроизведения исторического изменения иногда нужен зафиксированный набор полей. Для обработки текущего состояния может быть достаточно идентификатора и разрешённого запроса к основному сервису. Не смешивайте модели так, чтобы получатель принимал старый снимок за актуальную карточку.
Если передаётся ссылка, проверьте срок и область доступа. Публичный адрес не должен незаметно раскрывать закрытые материалы. Если передаются данные, определите правила журналирования и хранения у каждого получателя. Контракт касается не только удобства разработки, но и реального пути информации между сервисами.
Повторы и порядок
Один и тот же факт может доставляться повторно после временной ошибки. Идентификатор события помогает распознать повтор. Но бизнес-операция получателя также должна быть защищена от дублирования. Наличие уникального поля не гарантирует правильность, если приложение его не проверяет перед изменением данных.
Порядок доставки может отличаться от порядка возникновения. Для связанных изменений полезно иметь версию объекта или другое правило актуальности. Позднее событие о прежнем состоянии не должно откатывать уже применённое новое значение без проверки. Конкретный механизм зависит от вашей архитектуры и гарантий транспорта.
Не обещайте «доставку ровно один раз» только по наличию webhook. Определите, что гарантирует отправитель, что сохраняет получатель и как разбирается неопределённый результат. Эти правила лучше проверить отказом сервиса, чем обнаруживать их отсутствие по дубликатам обращений в рабочей CRM.
Документация и приёмка
Для каждого типа сохраните описание полей, допустимые значения и несколько вымышленных примеров. Отдельно покажите неизвестное поле, неподдерживаемую версию и повтор. Примеры не должны содержать настоящие токены, клиентские сообщения или случайные рабочие идентификаторы, которые дают доступ к данным.
Проверьте отправителя и получателя независимо. Старый получатель должен переживать совместимое изменение, а несовместимое — обрабатывать согласно договорённости. Затем испытайте задержку, повтор и восстановление. Успешная приёмка означает, что команда может объяснить смысл события и результат его обработки без устного пересказа автора интеграции.
Поле отсутствует или имеет пустое значение
Опишите разницу между отсутствующим полем, пустой строкой и явным пустым значением, если оно поддерживается схемой. Получатели часто трактуют их по-разному: оставить прежнее значение, очистить его или отклонить событие. Без договорённости небольшое изменение отправителя способно стереть данные в CRM, хотя разработчик хотел лишь не передавать неизвестный параметр.
Для изменения объекта особенно важно отличать снимок от частичного обновления. Если событие содержит только изменившиеся поля, отсутствие остальных не должно означать их удаление. Если передаётся полный снимок, получатель должен знать его полноту и версию. Это правило стоит показать отдельными примерами в документации.
На тесте отправьте один тип события с заполненным значением, без поля и с предусмотренным пустым вариантом. Проверьте итоговую карточку и диагностический результат. Затем повторите сценарий старым получателем, если такая совместимость заявлена. Приёмка должна подтверждать смысл каждого варианта, а не только способность JSON-парсера прочитать сообщение без синтаксической ошибки. Так контракт становится договором о поведении, а не просто списком возможных названий полей.
Источники
Исходные обновления описаны в Telegram Bot API: Update. Общие понятия конверта событий представлены в спецификации CloudEvents. Собственный контракт приложения следует документировать отдельно от этих интерфейсов.