Готовая serverless-система для приема заявок с сайта без Make, n8n и других внешних webhook-сервисов. Особенно актуально для РФ, где у части пользователей могут нестабильно работать зарубежные webhook-сервисы или внешние интеграции.
Проект принимает заявки с сайта, отправляет их в Telegram-чат менеджеров, добавляет кнопку «Принять», сохраняет статус заявки в YDB и через 5 минут отправляет напоминание, если заявку никто не взял в работу.
По стоимости такая схема на небольшом и среднем объеме обычно получается либо бесплатной, либо очень дешевой.
Подходит для интернет-магазинов, лендингов, сервисных сайтов и любых форм, где важно не потерять заявку.
- Принимать заявки с сайта через HTTP-запрос.
- Отправлять уведомления в Telegram.
- Добавлять inline-кнопку «Принять».
- Записывать заявку в YDB со статусом
pending. - Менять статус заявки на
accepted, когда менеджер нажал кнопку. - Показывать, кто именно принял заявку.
- Через 5 минут отправлять напоминание, если заявку никто не принял.
- Поддерживать разные типы заявок с разными текстами сообщений.
Сейчас предусмотрены 4 типа заявок:
| Тип заявки | Описание | Кнопка в Telegram | Напоминание |
|---|---|---|---|
callback_request |
Обратный звонок | ✅ Принять звонок |
🚨 Звонок не принят 5 минут |
one_click_order |
Заказ в один клик | ✅ Принять заказ |
🚨 Заказ в один клик не принят 5 минут |
preorder_request |
Предзаказ товара | ✅ Принять предзаказ |
🚨 Предзаказ не принят 5 минут |
alternative_request |
Подбор альтернативы | ✅ Принять подбор |
🚨 Подбор альтернативы не принят 5 минут |
На небольшом объеме такая схема обычно укладывается в бесплатные лимиты Yandex Cloud.
На одну заявку примерно приходится:
- 1 вызов функции
create-request; - 1 отправка сообщения в Telegram;
- 1 запись в YDB;
- 1 отправка сообщения в Message Queue;
- 1 вызов
reminderчерез 5 минут; - 1 чтение из YDB;
- иногда 1 вызов
accept-requestпри нажатии кнопки; - 1 обновление записи в YDB.
Примерно:
| Заявок в месяц | Вызовы функций | Запросы к очереди | Операции YDB | Ориентировочная стоимость |
|---|---|---|---|---|
| 100 | до 300 | около 100 | несколько сотен | обычно 0 ₽ |
| 1 000 | до 3 000 | около 1 000 | несколько тысяч | обычно 0 ₽ |
| 10 000 | до 30 000 | около 10 000 | десятки тысяч | обычно 0 ₽ |
| 100 000 | до 300 000 | около 100 000 | сотни тысяч | близко к 0 ₽ или очень дешево |
Почему так:
- Cloud Functions дают бесплатный ежемесячный объем: первые 1 000 000 вызовов и 10 ГБ×час выполнения.
- Message Queue дает первые 100 000 запросов к очереди в месяц бесплатно.
- YDB Serverless дает бесплатный ежемесячный объем операций и небольшой объем хранения.
- Telegram Bot API отдельно не тарифицируется.
Сайт
↓ POST-запрос
Cloud Function #1: create-request
├─→ Telegram: сообщение с кнопкой “Принять”
├─→ YDB: запись заявки со статусом pending
└─→ Message Queue: request_id с задержкой 5 минут
Telegram inline-кнопка
↓ webhook
Cloud Function #2: accept-request
├─→ YDB: pending → accepted
└─→ Telegram: “Заявка принята”, кто принял
Message Queue через 5 минут
↓ trigger
Cloud Function #3: reminder
├─→ читает заявку из YDB
├─→ если status = pending, отправляет напоминание
└─→ если status = accepted, ничего не делает
functions/
create-request/
index.js
package.json
accept-request/
index.js
package.json
reminder/
index.js
package.json
examples/
frontend-payloads.js
ydb-schema.sql
.env.example
README.md
Нужны:
- аккаунт в Yandex Cloud;
- Telegram-бот;
- Telegram-чат или группа для заявок;
- Yandex Cloud Functions;
- Yandex Managed Service for YDB в режиме Serverless;
- Yandex Message Queue;
- триггер Message Queue → Cloud Function.
- Откройте BotFather в Telegram.
- Создайте нового бота.
- Сохраните токен бота.
Пример переменной:
TELEGRAM_BOT_TOKEN=1234567890:your_bot_token_here- Создайте группу или используйте существующую.
- Добавьте туда бота.
- Получите
chat_idгруппы. - Добавьте его в переменные окружения.
TELEGRAM_CHAT_ID=-1001234567890Для тестового чата можно использовать отдельную переменную:
TELEGRAM_CHAT_ID_TEST=-1009876543210В Yandex Cloud создайте базу YDB в режиме Serverless.
Нужны будут:
YDB_ENDPOINT=grpcs://ydb.serverless.yandexcloud.net:2135
YDB_DATABASE=/ru-central1/your-cloud-id/your-folder-id/your-database-idПример схемы:
CREATE TABLE callback_requests (
request_id Utf8 NOT NULL,
request_type Utf8,
status Utf8,
phone Utf8,
name Utf8,
comment Utf8,
page_url Utf8,
product_name Utf8,
product_price Utf8,
message_id Utf8,
created_at Utf8,
accepted_by Utf8,
accepted_at Utf8,
PRIMARY KEY (request_id)
);Создайте стандартную очередь, например:
callback-reminders
Рекомендуемые настройки:
Тип: Standard
Задержка доставки: 300 секунд
Срок хранения сообщений: 4 дня
Размер группы для триггера: 1
Сохраните URL очереди:
YMQ_QUEUE_URL=https://message-queue.api.cloud.yandex.net/your-folder-id/your-queue-id/callback-remindersСоздайте сервисный аккаунт, например:
lead-router-sa
Для простого запуска можно выдать ему роли:
functions.functionInvoker
ymq.writer
editor
editor можно использовать на старте для упрощения настройки триггера. После проверки лучше заменить его на более точные права.
Для отправки сообщений в Message Queue через AWS SQS SDK нужен статический ключ сервисного аккаунта.
Добавьте в переменные:
AWS_REGION=ru-central1
AWS_ACCESS_KEY_ID=your_access_key_id
AWS_SECRET_ACCESS_KEY=your_secret_access_keyTELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
TELEGRAM_CHAT_ID_TEST=
YDB_ENDPOINT=
YDB_DATABASE=
YMQ_QUEUE_URL=
AWS_REGION=ru-central1
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
TELEGRAM_CHAT_ID_TEST=
YDB_ENDPOINT=
YDB_DATABASE=TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
TELEGRAM_CHAT_ID_TEST=
YDB_ENDPOINT=
YDB_DATABASE=Эта функция принимает заявку с сайта.
Что делает:
- Проверяет входящие данные.
- Определяет тип заявки.
- Отправляет сообщение в Telegram.
- Записывает заявку в YDB со статусом
pending. - Кладет
request_idв Message Queue.
Поддерживаемые типы:
callback_request
one_click_order
preorder_request
alternative_request
Эта функция принимает webhook от Telegram.
Что делает:
- Получает нажатие inline-кнопки.
- Достает
request_id. - Находит заявку в YDB.
- Меняет статус на
accepted. - Сохраняет, кто принял заявку.
- Убирает кнопку из исходного сообщения.
- Отправляет сообщение в чат.
Пример для звонка:
✅ Звонок принят
Принял: @username
Пример для заказа:
✅ Заказ принят
Принял: @username
Эта функция вызывается триггером Message Queue через 5 минут.
Что делает:
- Получает
request_idиз очереди. - Читает заявку из YDB.
- Если
status = accepted, ничего не делает. - Если
status = pending, отправляет напоминание в Telegram.
Примеры напоминаний:
🚨 Звонок не принят 5 минут
🚨 Заказ в один клик не принят 5 минут
🚨 Предзаказ не принят 5 минут
🚨 Подбор альтернативы не принят 5 минут
После создания функции accept-request нужно привязать к ней Telegram webhook.
URL функции будет выглядеть примерно так:
https://functions.yandexcloud.net/id-вашей-функции
Webhook должен принимать callback_query.
Пример запроса:
https://api.telegram.org/bot<TOKEN>/setWebhook?url=https%3A%2F%2Ffunctions.yandexcloud.net%2Fyour-function-id&allowed_updates=%5B%22callback_query%22%5D
Проверить webhook можно так:
https://api.telegram.org/bot<TOKEN>/getWebhookInfo
В ответе должен быть URL функции и:
{
"allowed_updates": ["callback_query"]
}Создайте триггер:
Тип: Message Queue
Очередь: callback-reminders
Запускаемый ресурс: Function
Функция: reminder
Размер группы: 1
Время ожидания: 0
После создания триггер может начать работать не мгновенно. Иногда нужно подождать несколько минут.
fetch('https://functions.yandexcloud.net/your-create-request-function-id', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'callback_request',
name: 'Дмитрий',
phone: '+7 (999) 123-45-67',
page_url: window.location.href,
page_title: document.title,
submitted_at: new Date().toLocaleString(),
}),
});fetch('https://functions.yandexcloud.net/your-create-request-function-id', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'one_click_order',
full_name: 'Дмитрий',
phone: '+7 (999) 123-45-67',
comment: 'Позвонить после 14:00',
product_name: 'Бензопила Makita',
product_price: '33 890 ₽',
page_url: window.location.href,
page_title: document.title,
submitted_at: new Date().toLocaleString(),
}),
});fetch('https://functions.yandexcloud.net/your-create-request-function-id', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'preorder_request',
name: 'Дмитрий',
phone: '+7 (999) 123-45-67',
product_name: 'Мойка высокого давления',
page_url: window.location.href,
page_title: document.title,
submitted_at: new Date().toLocaleString(),
}),
});fetch('https://functions.yandexcloud.net/your-create-request-function-id', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'alternative_request',
name: 'Дмитрий',
phone: '+7 (999) 123-45-67',
product_name: 'Товар, которого нет в наличии',
page_url: window.location.href,
page_title: document.title,
submitted_at: new Date().toLocaleString(),
}),
});📞 Новая заявка на обратный звонок
Имя: Дмитрий
Телефон: +7 (999) 123-45-67
Страница: https://example.ru/product/example
❗ Новый заказ в один клик
Данные о клиенте:
ФИО: Дмитрий
Телефон: +7 (999) 123-45-67
Комментарий: Позвонить после 14:00
Данные о товаре:
Товар: Бензопила Makita
Цена: 33 890 ₽
Страница: https://example.ru/product/example
📦 Новая заявка на предзаказ
Имя: Дмитрий
Телефон: +7 (999) 123-45-67
Товар: Мойка высокого давления
🔎 Новая заявка на подбор альтернативы
Имя: Дмитрий
Телефон: +7 (999) 123-45-67
Товар: Товар, которого нет в наличии
Перед публикацией проекта или деплоем обязательно:
- не храните токены и ключи в коде!;
- используйте переменные окружения;
- не коммитьте
.env; - не выкладывайте реальные номера телефонов клиентов;
- не выкладывайте реальные
chat_id, токены ботов и AWS static keys; - после тестов лучше заменить широкую роль
editorна более точные роли.
Идеи для развития:
- добавить повторное напоминание через 15 минут;
- добавить разные Telegram-чаты для разных типов заявок, на разные отделы;
- добавить логирование источника заявки и UTM-меток;
- добавить статус
expired; - добавить простую админку заявок;
- добавить отправку в CRM;
- добавить скрытую защиту от спама;
- добавить прочие функции - inline кнопки к каждой заявке.
MIT
