Бот для онлайн-записи — один из самых востребованных сценариев у малого и среднего сервисного бизнеса в России: салоны красоты, медицинские клиники, барбершопы, фитнес-студии, СТО, репетиторы, ветклиники. Снаружи это «выберите время», внутри — расписание, конфликты, отмены, оплата, напоминания и интеграция с уже работающей системой записи.
Главная боль администратора — приём заявок по телефону и в соцсетях: пропущенные звонки, ошибки в журнале, ручной перенос, no-show без штрафа. Бот в MAX закрывает первичный канал записи без передачи телефона: пользователь уже залогинен в мессенджере, не вводит логин-пароль и не ставит лишнее приложение. Для бизнеса это снижение нагрузки на ресепшн на 40–60% и рост повторных визитов за счёт удобной отмены и переноса в один клик.
Разберём архитектуру по слоям: что видит клиент, как считаются слоты, где живёт расписание, как защититься от двойного бронирования, как снизить no-show, и куда подключаются YClients, Altegio, Dikidi и 1С:Медицина.
Поверхность бота: что видит клиент
Универсальный сценарий записи одинаков для салона, клиники и автосервиса:
- Открыл бота → приветствие и кнопка «Записаться».
- Выбрал филиал (если сеть).
- Выбрал услугу из плоского списка с длительностью и ценой.
- Выбрал мастера или специалиста (опционально, либо «любой свободный»).
- Выбрал день и время из доступных слотов.
- Подтвердил, ввёл имя и телефон (если ещё не сохранён).
- Получил подтверждение и серию напоминаний.
- После визита — приглашение оставить отзыв и накопить бонусы.
- В любой момент может отменить или перенести запись.
Это и есть ядро. Программа лояльности, рекомендации, листы ожидания — поверх. Ключевая метрика поверхности — глубина воронки: сколько кнопок и экранов между «открыл бота» и «получил подтверждение». Для MAX комфортный потолок — 5–6 шагов, дальше начинается падение конверсии на 8–12% за каждый лишний экран.
Mini App в MAX vs inline-кнопки для календаря
Календарь — самый сложный экран в боте записи. Здесь два архитектурных подхода:
| Критерий | Inline-клавиатура | Mini App в MAX |
|---|---|---|
| UX выбора даты | Скролл по неделям кнопками | Привычный календарь с месяцем |
| Скорость первого экрана | 200–400 мс | 1.2–2.5 с (загрузка WebView) |
| Глубина горизонта | Удобно до 14 дней | Месяц и больше |
| Сложность разработки | 1× | 2.5× (фронт + initData + бэк) |
| Перенос/отмена | В 2 тапа | В 2 тапа, но с визуальным календарём |
| Доступность для оффлайн-кэша | Лучше | Хуже |
| Подходит для | Барбершоп, СТО, репетитор | Клиника с расписанием на месяц, фитнес |
Практическое правило: до 30 слотов в день и горизонт 1–2 недели — берите inline. Сетка фитнес-классов на месяц или клиника с десятками врачей и слотов на 60 дней вперёд — Mini App. Гибрид тоже работает: inline для типичной записи и Mini App для «посмотреть полный календарь».
Mini App в MAX открывается через стандартный для MAX Bot API механизм WebView с initData; авторизация пользователя проверяется на бэке по подписи. Не доверяйте user_id из query string без верификации подписи — это классическая дыра, через которую можно записаться от имени соседа.
Модель данных
Скелет схемы БД для бота записи:
- Филиалы (адрес, часы работы, часовой пояс, услуги).
- Услуги (название, длительность, цена, к кому из мастеров привязана, к каким филиалам).
- Мастера (ФИО, специализация, рабочие часы по дням недели, привязка к филиалу).
- Расписание-исключения (выходные, отпуска, нестандартные смены, технические перерывы).
- Записи (клиент, услуга, мастер, филиал, время начала, статус, источник).
- Клиенты (контакт MAX, телефон, история визитов, no-show счётчик, теги).
- Очередь напоминаний (запись, тип, время отправки, статус).
Ключевой принцип — слоты не хранятся, а вычисляются из расписания мастера и существующих записей на каждый запрос. Хранить слоты отдельно — путь к рассинхронизации, особенно когда администратор правит расписание в основной CRM.
CREATE TABLE appointments (
id BIGSERIAL PRIMARY KEY,
branch_id INT NOT NULL,
master_id INT NOT NULL,
service_id INT NOT NULL,
client_id BIGINT NOT NULL,
starts_at TIMESTAMPTZ NOT NULL,
ends_at TIMESTAMPTZ NOT NULL,
status TEXT NOT NULL DEFAULT 'confirmed',
source TEXT NOT NULL DEFAULT 'max_bot',
deposit_paid NUMERIC DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT now(),
EXCLUDE USING gist (
master_id WITH =,
tstzrange(starts_at, ends_at, '[)') WITH &&
) WHERE (status IN ('confirmed', 'pending'))
);
EXCLUDE USING gist с диапазоном времени — самый честный способ запретить пересечение записей у одного мастера на уровне БД. Это страховка от багов в коде расчёта слотов.
Алгоритм поиска слотов
Запрос «свободно ли в четверг с 14:00 на стрижку (40 мин) у мастера X»:
- Берём рабочие часы мастера на четверг с учётом часового пояса филиала.
- Применяем расписание-исключения (отпуск → пусто, сокращённый день → урезаем).
- Вычитаем уже занятые записи с буфером 5–10 минут между ними.
- Получаем массив свободных промежутков.
- Внутри каждого ищем слоты длиной 40 минут с шагом сетки (15 или 30 минут).
- Возвращаем кандидатов, отсортированных по времени.
Подводные камни:
- Перерывы между записями. Большинство мастеров хотят 5–10 минут на «передохнуть». Это конфигурируется на уровне мастера и услуги.
- Часовые пояса. Если бизнес в нескольких городах, считаем всё в UTC, отображаем в локальном поясе филиала. Не клиента — клиент может быть в Калининграде, а салон в Хабаровске.
- Сложные услуги. Окрашивание = «нанесение 30 мин → выдержка 40 мин → смывка 20 мин». Технологически мастер занят только в первый и третий блок, в выдержке может принимать другого клиента. Это ломает наивный алгоритм «один блок времени».
- Кабинеты как отдельный ресурс. В клинике на одну услугу нужны и врач, и кабинет, и оборудование. Слот свободен, только если все три ресурса доступны одновременно.
Конфликты двойного бронирования
Два клиента нажали «забронировать» одновременно на один и тот же слот. Без защиты оба получат подтверждение, мастер увидит коллизию утром, один клиент уйдёт с обидой. Решение в три приёма:
- Distributed lock на слот в Redis:
SET slot:{master}:{ts} {user_id} NX EX 60на время чек-аута. Кто первый поставил ключ, тот и бронирует. - Транзакция с проверкой пересечения при финальном
INSERTвappointments. Если БД (черезEXCLUDE USING gist) отказала — показываем «слот только что заняли, выберите другое время». - Идемпотентность создания записи по ключу
(client_id, slot_start, master_id)— если клиент дважды нажал «Подтвердить», вторая запись не создаётся.
Интеграция с системами записи
Если у бизнеса уже есть отраслевая CRM (а это типично для салонов и клиник), бот не дублирует логику, а становится фронт-каналом. Расписание и записи живут в основной системе, бот ходит в её API.
| Система | Сегмент | API | Webhook | Сложность |
|---|---|---|---|---|
| YClients | Бьюти, фитнес, медицина | REST JSON, токен | Есть, надёжный | Средняя |
| Altegio | Бьюти, фитнес (бывш. YClients CIS) | REST JSON | Есть | Средняя |
| Dikidi | Бьюти, барбершопы | REST JSON | Частичный | Простая |
| Sonline | Сервисы, фитнес | REST JSON | Есть | Простая |
| 1С:Медицина | Клиники | REST + OData | Через расширения | Высокая |
| IDENT | Стоматология | REST JSON | Есть | Средняя |
Универсальный паттерн интеграции:
- На каждый запрос слотов от клиента — запрос в API системы записи. Кэш на 30–60 секунд для частых запросов одного и того же дня.
- На создание записи — синхронный вызов API системы. Запись создаётся именно там, бот сохраняет только «зеркало» с
external_id. - На изменения, сделанные администратором (отмена, перенос, новый мастер) — webhook в бот. Если webhook ненадёжен, поверх ставим пуллинг раз в 5–10 минут на изменённые записи за последний час.
Дублировать расписание в собственной БД бота — путь к рассинхрону. Администратор подвинет запись в YClients, клиент придёт по старому времени, мастер скажет «у меня тут другой человек».
Архитектура: webhook + пуллинг для надёжности
Webhook от системы записи — основной канал свежих данных. Но webhooks падают по сотне причин: TLS-ошибки, таймауты, ретраи без идемпотентности, очереди на стороне поставщика. Полагаться только на push — рискованно.
Рабочая схема:
- Push-канал. Webhook прилетает на наш HTTPS-эндпоинт, проверяем подпись, кладём в очередь (Redis Streams / RabbitMQ), отвечаем 200 быстро.
- Worker разбирает очередь, обновляет зеркало в нашей БД, отправляет уведомления клиентам в MAX.
- Pull-канал. Раз в 5–10 минут фоновая job опрашивает API «дай изменения с момента T» и сверяет с зеркалом. Расхождения логируются и применяются.
Pull догоняет потерянные webhooks. Без него вы узнаёте о пропущенном событии только когда клиент жалуется «мне никто не напомнил».
Перенос, отмена, штраф, лист ожидания
Отмена в один тап — обязательная функция. Если её нет, клиенты не отменяют, а просто не приходят (no-show). Правила бизнеса:
- Бесплатная отмена за N часов до визита (обычно 24 ч в бьюти, 4 ч у репетитора).
- Платная отмена в последний момент — списание депозита целиком или частично.
- Перенос — отдельный сценарий: клиент видит свободные слоты на ближайшие дни, выбирает новый.
- Штраф за no-show — отметка в карточке клиента, при следующей записи требуется 100% предоплата.
Лист ожидания — мощная и недооценённая функция. Клиент не нашёл удобного времени → жмёт «Уведомить, если освободится». При отмене другого клиента бот рассылает приглашение первым 2–3 в листе. Кто первый подтвердил — забрал слот. Это закрывает 30–50% освободившихся слотов, которые иначе остались бы пустыми.
Каждое изменение записи фиксируется в логе с timestamp и инициатором (клиент / администратор / автомат) — для разбора спорных ситуаций и аналитики причин отмен.
Напоминания и снижение no-show
Без напоминаний 15–25% клиентов не приходят. С грамотными напоминаниями — обычно 5–10%. Минимальная схема напоминаний:
- За 24 часа — «Завтра в 14:00 у вас запись к мастеру Анне на стрижку. Подтвердите кнопкой». Кнопки: «Да, приду» / «Отменить» / «Перенести».
- За 2 часа — короткое напоминание с адресом и схемой проезда.
- За 30 минут — для длинных услуг или клиентов из дальнего пригорода.
- При неподтверждении за 24 ч — административный сигнал: возможно, слот стоит освободить.
Технически напоминания — это отложенные задачи в очереди (BullMQ, Asynq, sidekiq-аналог в Go). Очередь должна переживать перезапуск сервиса (персист на диск) и иметь идемпотентность: один и тот же appointment_id × reminder_type не должен отправиться дважды, даже при ретраях после падения worker.
async def schedule_reminders(appt_id: int, starts_at: datetime):
plan = [
("24h", starts_at - timedelta(hours=24)),
("2h", starts_at - timedelta(hours=2)),
("30m", starts_at - timedelta(minutes=30)),
]
for kind, fire_at in plan:
if fire_at <= datetime.now(tz=timezone.utc):
continue
await queue.enqueue(
"send_reminder",
{"appt_id": appt_id, "kind": kind},
run_at=fire_at,
dedup_key=f"reminder:{appt_id}:{kind}",
)
Pre-payment и залог через бота
Предоплата 20–50% или фиксированный залог 500–1500 ₽ резко снижает no-show: клиент, который заплатил, приходит в 92–95% случаев против 75–85% без предоплаты. Это работает особенно жёстко для популярных мастеров и дорогих услуг.
Технически — связка с эквайером (ЮKassa, Тинькофф, СБП по QR), статус заказа paid_partial подтверждает запись, без оплаты бронь снимается через 15 минут (slot lock в Redis истекает сам). Сдачу оплачивает клиент на месте картой или наличными.
Возврат залога при бесплатной отмене за 24 ч — обязательный сценарий. По 161-ФЗ и правилам платёжных систем — возврат на ту же карту в течение 10 рабочих дней. Если вернуть «бонусами на бота» — клиент пожалуется в банк, банк сделает чарджбек, эквайер возьмёт штраф 1500–2500 ₽ с салона.
Программа лояльности и отзывы
Бот в MAX — естественное место для программы лояльности услугового бизнеса. Привязка к записям делает её ощутимой: после каждого визита клиент видит «+150 баллов за стрижку», «осталось 350 баллов до бесплатной укладки».
Минимальный набор механик:
- Кешбек баллами — 3–10% от чека после визита (не после оплаты, иначе баллы уйдут на возвраты).
- Уровни клиента (Базовый / Серебро / Золото) — растут от суммы за 6–12 месяцев, дают повышенный кешбек и приоритет в листе ожидания.
- Дни рождения — автоматическая скидка или подарок.
- Реферальная программа — приглашающий получает баллы после первого визита приглашённого.
- Серии услуг (абонементы) — оплата 5 визитов авансом со скидкой 15%.
Отзывы пост-визит — отдельный сценарий. Через 3–5 часов после визита бот спрашивает «Как прошло?» с шкалой 1–5 или эмодзи. Оценка 4–5 → просьба оставить публичный отзыв (на 2ГИС, Яндекс.Картах) с готовой ссылкой. Оценка 1–3 → «Расскажите, что не так» с эскалацией администратору, без публикации. Это NPS-фильтр: негатив едет в личку, позитив — в публичные источники. По опыту бьюти-сетей такая воронка даёт прирост публичных отзывов в 4–6 раз и отвечает на негатив до того, как он стал публичным.
Аналитика бота записи
Полезные метрики, которые бот собирает сам:
- Конверсия из открытия в запись — сколько пользователей дошли от
/startдо подтверждённой записи. - No-show rate — по мастерам, услугам, дням недели, часам, источникам трафика.
- Загруженность мастеров — % занятого рабочего времени, разрыв между лучшим и худшим мастером.
- Средний чек через бота vs через ресепшн — обычно через бота на 8–15% выше за счёт допродажи в карточке услуги.
- Retention 30/60/90 дней — доля клиентов, которые вернулись за повторной записью.
- Источники записей по UTM — какие каналы трафика приводят лучших клиентов.
- Воронка отмен и переносов — сколько отменили, перенесли, не пришли молча.
- Время от открытия бота до записи — индикатор юзабилити: норма 2–4 минуты, выше 8 — проблемы со сценарием.
| Метрика | Норма | Тревога |
|---|---|---|
| Конверсия открытие → запись | 22–35% | менее 15% |
| No-show без предоплаты | 10–18% | более 25% |
| No-show с предоплатой | 4–8% | более 12% |
| Recovery листа ожидания | 30–50% | менее 20% |
| Доля повторных за 60 дней | 35–55% | менее 25% |
| Средний NPS | 8.5–9.3 | менее 7.5 |
Эти данные подтягиваются в дашборд (Metabase, Superset, Grafana поверх Postgres). Раз в неделю — автоматический отчёт владельцу в личку MAX от того же бота.
Multi-локационная сеть
Сеть из 3+ филиалов — отдельный класс задач. Что меняется:
- Выбор филиала становится первым шагом сценария. Удобно подсказать ближайший по геолокации, но не навязывать.
- Услуги и цены могут отличаться по филиалам (центр vs спальный район). Прайс хранится по паре
(branch_id, service_id). - Мастера привязаны к филиалу, иногда работают в нескольких — таблица
master_branchesмногие-ко-многим. - Расписание и слоты считаются на уровне филиала + мастера. Кэш — отдельно по филиалу.
- Программа лояльности — общая на сеть (баллы накоплены в одном салоне, потрачены в другом).
- Предоплата уходит на счёт юр.лица филиала или общий счёт сети — это решает бухгалтерия и эквайер.
Аналитика по сети должна резаться по филиалам: загруженность одного может быть 90%, другого — 45%. Это сигнал для маркетинга и пересмотра графиков мастеров.
Чек-лист готовности бота к запуску
- Универсальный сценарий «услуга → мастер → дата → время → подтверждение» проходится за 5–6 шагов.
- Слоты вычисляются на лету из расписания CRM, не хранятся в собственной БД.
-
EXCLUDE USING gistили distributed lock защищает от пересечения записей. - Webhook от CRM + пуллинг раз в 5–10 минут как страховка.
- Идемпотентность создания записи и отправки напоминаний.
- Напоминания за 24 ч, 2 ч (опционально 30 мин), переживают перезапуск сервиса.
- Кнопки «Отменить» и «Перенести» прямо в напоминании, без ввода команд.
- Лист ожидания на популярные слоты с авторассылкой при освобождении.
- Pre-payment / залог через ЮKassa или СБП с автоматическим возвратом при отмене за N часов.
- Чек по 54-ФЗ уходит в ОФД при оплате депозита.
- Программа лояльности привязана к фактическому визиту, не к оплате.
- Отзывы пост-визит с NPS-фильтром: позитив наружу, негатив администратору.
- Аналитика: конверсия, no-show, загрузка, retention, средний чек.
- Multi-локация — выбор филиала первым шагом, цены и расписание по филиалу.
- Согласие на обработку ПДн собрано до записи (152-ФЗ).
Итого
Бот для записи в MAX — не «форма с датой», а связка из расписания, расчёта слотов с защитой от двойного бронирования, очереди напоминаний, эквайринга для предоплаты и интеграции с уже работающей CRM. При продуманной архитектуре проект занимает 3–5 недель и даёт измеримый эффект: 40–60% разгрузка ресепшна, no-show с 20% до 5–8%, средний чек выше на 10–15%, retention выше на 20–30% за счёт лояльности и удобной отмены.
Главное — не пытаться заменить YClients или 1С:Медицину собственной БД расписания. Бот — это новый канал записи и сервиса, а не вторая система учёта.
Частые вопросы
Сколько стоит бот для записи на услуги в MAX?
От 120 000 до 280 000 ₽ при разработке под ключ, срок 3–5 недель. В цену входит универсальный сценарий записи (услуга, мастер, дата, время), расчёт слотов с защитой от двойного бронирования через EXCLUDE USING gist, очередь напоминаний за 24 ч и 2 ч с идемпотентностью, отмены и переносы, базовая аналитика. Дополнительно: предоплата через ЮKassa или СБП плюс 30 000–60 000 ₽, интеграция с YClients/Altegio/Dikidi/1С:Медицина плюс 50 000–100 000 ₽, Mini App в MAX с визуальным календарём плюс 60 000–140 000 ₽, программа лояльности с уровнями и баллами плюс 40 000–80 000 ₽, multi-локация для сети филиалов плюс 30 000–60 000 ₽.
Как бот рассчитывает свободные слоты записи?
Слоты не хранятся, а вычисляются на лету при каждом запросе. Алгоритм: берём рабочие часы мастера на дату с учётом часового пояса филиала, применяем расписание-исключения (отпуска, сокращённые дни), вычитаем существующие записи с буфером 5–10 минут, получаем свободные промежутки, внутри ищем слоты нужной длины с шагом сетки 15 или 30 минут. Хранить слоты отдельно — путь к рассинхрону, особенно когда администратор правит расписание в основной CRM. Для конкурентности (два клиента жмут одновременно) ставим distributed lock в Redis на слот с TTL 60 секунд плюс EXCLUDE USING gist с диапазоном времени на уровне БД — это страховка от багов в коде.
Как уменьшить количество no-show через бота записи в MAX?
Тремя приёмами в комбинации. Напоминания за 24 ч с просьбой подтвердить кнопкой «Да, приду» / «Перенести» / «Отменить», за 2 ч короткое с адресом — снижают no-show с типичных 15–25% до 8–12%. Pre-payment или залог 500–1500 ₽ через ЮKassa или СБП — при отмене за 24 ч возврат на карту, при no-show удержание; снижает no-show до 4–8% для популярных мастеров и дорогих услуг. Отметка no-show в карточке клиента и автоматическое требование 100% предоплаты при следующей записи. Лист ожидания дополнительно закрывает 30–50% освободившихся слотов: при отмене бот рассылает приглашение первым в очереди.
Как интегрировать бот в MAX с YClients, Altegio, Dikidi или 1С:Медицина?
Бот работает как фронт-канал, расписание и записи живут в основной CRM. На каждый запрос слотов от клиента — запрос в API системы записи, кэш на 30–60 секунд для частых обращений к одному дню. На создание записи — синхронный вызов API CRM, бот сохраняет только зеркало с external_id. На изменения от администратора (отмена, перенос) — webhook от CRM в наш HTTPS-эндпоинт. Поверх webhook ставим пуллинг раз в 5–10 минут на изменённые записи за последний час — это страховка от потерянных push-событий. YClients, Altegio, Dikidi и Sonline — REST JSON с токеном, IDENT — тоже REST. 1С:Медицина — REST или OData через расширения, сложнее остальных. Срок интеграции 5–12 рабочих дней при готовом API. Дублировать расписание в собственной БД нельзя — гарантированный рассинхрон.
Нужен ли Mini App в MAX или хватит inline-кнопок для записи?
Зависит от глубины каталога услуг и горизонта расписания. До 30 слотов в день и горизонт 1–2 недели — берите inline-клавиатуру: первый экран за 200–400 мс, проще разработка, лучше работает в плохой связи. Сетка фитнес-классов на месяц или клиника с десятками врачей и слотов на 60 дней вперёд — Mini App с привычным календарём. Mini App дороже в 2.5 раза, открывается за 1.2–2.5 секунды и просаживает конверсию на загрузке, но даёт привычный UX визуального календаря. Гибрид часто оптимален: inline для типичной записи в 2–3 клика, Mini App по кнопке «Открыть полный календарь» для пользователей, кому нужен месяц вперёд. Авторизация в Mini App — по подписи initData; не доверяйте user_id из query string без проверки подписи на бэке.
Как настроить программу лояльности и сбор отзывов через бота?
Программа лояльности привязывается к фактическому визиту, а не к оплате — иначе баллы уйдут на возвраты. Базовый набор: кешбек 3–10% после визита, уровни клиента (Базовый, Серебро, Золото) от суммы за 6–12 месяцев, бонус ко дню рождения, реферальная программа с начислением после первого визита приглашённого, абонементы со скидкой 15% за оплату 5 визитов вперёд. Отзывы пост-визит — через 3–5 часов после визита бот спрашивает оценку 1–5. Оценка 4–5 — просьба оставить публичный отзыв на 2ГИС или Яндекс.Картах с готовой ссылкой. Оценка 1–3 — «расскажите, что не так» и эскалация администратору без публикации. Это NPS-фильтр: негатив едет в личку и решается, позитив выходит в публичные источники. У бьюти-сетей такая воронка даёт прирост публичных отзывов в 4–6 раз.
Какую аналитику собирает бот для записи на услуги?
Восемь полезных метрик. Конверсия из открытия бота в запись — главная воронка, норма 22–35%. No-show rate по мастерам, услугам, дням недели и источникам — норма 10–18% без предоплаты, 4–8% с предоплатой. Загруженность мастеров в процентах рабочего времени — даёт основу для пересмотра графиков. Средний чек через бота vs через ресепшн — обычно выше на 8–15% за счёт допродажи в карточке услуги. Retention 30/60/90 дней — норма 35–55% за 60 дней. Источники записей по UTM. Воронка отмен и переносов с причинами. Время от открытия бота до подтверждения записи — норма 2–4 минуты, выше 8 говорит о проблемах сценария. Метрики собираются в Postgres и подтягиваются в Metabase или Grafana, раз в неделю владельцу в MAX уходит автоматический сводный отчёт.