Tilda · 8 мин чтения

Webhook Тильды: как принять заявку на своём сервере

Webhook в форме Tilda даёт прямой способ забрать заявку и обработать её собственной логикой, а не только через готовые интеграции с CRM и почтой, которые тоже есть в конструкторе. Среди приёмщиков данных в настройках сайта есть отдельный тип подключения: Webhook. При отправке формы Tilda делает POST-запрос на URL, который вы укажете, и передаёт поля заявки обычными парами «имя=значение», а дальше ваш сервер сам решает, что делать с данными: записать заявку в базу, отправить уведомление в Telegram, посчитать стоимость или передать данные в свою систему. Ниже показываю, как принять такой webhook на обычном PHP-хостинге, без выделенного сервера и без посредников.

Как включить приём вебхука в настройках сайта Tilda

Адрес обработчика задаётся не в блоке с формой, а в настройках сайта: Настройки сайта, раздел Формы, пункт Webhook. Указываю адрес своего скрипта, например https://mysite.ru/tilda-webhook.php, при необходимости ставлю галочку отправки куки и сохраняю. После этого открываю страницу с формой, в меню «Контент» блока отмечаю сервис приёма данных Webhook, сохраняю и публикую страницу заново, иначе новый получатель заявки не подключится.

Требования к скрипту в справке заданы жёстко: адрес должен быть доступен, скрипт обязан ответить в течение пяти секунд и работать по HTTPS. Если ответа нет, система сделает ещё две попытки, каждую через минуту.

Отдельной кнопки тестовой отправки у поля URL нет. Тестовый запрос Tilda отправляет сама: сразу после подключения Webhook на указанный адрес уходит POST с данными test=test, и от скрипта ожидается ответ 200 OK. По логам сервера в этот момент уже видно, доходит ли запрос вообще, а состав полей настоящей заявки смотрю на первой живой отправке формы.

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

На одном сайте обычно несколько форм: заявка с лендинга, форма подбора товара, форма подписки на рассылку. Для каждой формы вебхук настраивается отдельно, и можно указать либо один общий обработчик, либо развести формы по разным URL, если логика заметно отличается, например заявка идёт в таблицу лидов, а подписка сразу добавляет адрес в список рассылки.

Что приходит на ваш URL: структура запроса

Tilda делает обычный POST формы, а не JSON: все поля приходят в $_POST парами «имя=значение», где имена совпадают с именами полей, которые вы задали в настройках формы, например Name, Phone, Email. Если «имя переменной» у поля не менять, оно придёт с первой буквой в верхнем регистре. Кроме полей заявки приходят служебные tranid (уникальный номер заявки из раздела «Заявки») и formid (номер блока, с которого была отправка). Часть символов в значениях экранирована: вместо @ приходит %40, вместо двоеточия %3a, поэтому значения прогоняю через urldecode. Точный набор ключей зависит от того, какие поля добавлены в конструкторе и как они названы, поэтому на практике я всегда сначала смотрю реальный запрос: логирую его целиком при первом тесте, а уже потом пишу код под конкретные названия полей.

Пример того, что обычно прилетает на сервер (реальные ключи будут отражать поля именно вашей формы):

Name=test+name
Phone=0123456789
Email=test%40email.com
Comments=example+comment
tranid=467251%3A8442970
formid=form48844953

PHP-обработчик вебхука на обычном хостинге

Для приёма вебхука не нужен отдельный сервер, VPS или процесс на Node.js, который постоянно крутится в фоне: обычный PHP-скрипт на хостинге, где уже лежит сайт, справляется полностью, потому что Tilda делает один HTTP-запрос и ждёт от него быстрый ответ.

<?php
$data = array_map(static function ($value) {
    return is_string($value) ? urldecode($value) : $value;
}, $_POST);

if (!$data) {
    http_response_code(400);
    exit;
}

$name = trim($data['Name'] ?? '');
$phone = trim($data['Phone'] ?? '');
$email = trim($data['Email'] ?? '');

$payload = json_encode($data, JSON_UNESCAPED_UNICODE);

$pdo = new PDO('mysql:host=localhost;dbname=site;charset=utf8mb4', 'db_user', 'db_pass');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare('INSERT INTO leads (name, phone, email, payload, created_at) VALUES (?, ?, ?, ?, NOW())');
$stmt->execute([$name, $phone, $email, $payload]);

http_response_code(200);

Скрипт читает данные из $_POST, а не из php://input, потому что Tilda присылает обычную форму, а не JSON. Значения прогоняю через urldecode: в справке Тильды сказано, что часть символов перед передачей экранируется, например вместо @ приходит %40. Весь набор полей сохраняю в отдельную колонку: если в конструкторе изменится название поля или добавится новое, данные не потеряются, их можно будет перечитать из лога уже после правки кода. Ответ 200 нужен и на тестовый запрос test=test, который Tilda отправляет сразу после подключения приёмщика.

Тяжёлую логику лучше не запускать внутри самого обработчика вебхука. Если после заявки нужно дёрнуть внешний API, посчитать что-то небыстрое или сходить в другую систему, надёжнее сначала быстро сохранить сырые данные и ответить Tilda, а уже отдельным шагом обрабатывать сохранённые записи, читая их из базы.

Бесплатный материал

🎁 Полезный скрипт в подарок

Подпишитесь на Telegram - пришлю готовый скрипт по этой теме.

Без спама. Отписка в 1 клик.

Секретный токен вместо доверия по умолчанию

Подписи запроса вроде HMAC-подписи у вебхука Tilda нет, поэтому обработчик должен сам убедиться, что запрос пришёл именно от вашей формы, а не от кого попало, кто узнал адрес скрипта. Фильтровать по IP ненадёжно: адреса серверов Tilda нигде не зафиксированы как постоянные и могут меняться, а обработчик, который перестанет принимать заявки после такой смены, заметят не сразу.

Проще добавить в сам адрес вебхука произвольный секретный параметр, например https://mysite.ru/tilda-webhook.php?token=a91f7c3e, и на сервере первым делом сверить его со значением из конфига:

<?php
$expectedToken = 'a91f7c3e';

if (($_GET['token'] ?? '') !== $expectedToken) {
    http_response_code(403);
    exit;
}

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

Сохраняю заявку и уведомляю в Telegram

После проверки токена и записи заявки в базу отправляю короткое уведомление в Telegram, проверять таблицу лидов руками неудобно, а сообщение приходит за пару секунд. Для одного уведомления не нужен полноценный бот на aiogram с обработкой команд, достаточно прямого запроса к Bot API.

<?php
$botToken = 'BOT_TOKEN';
$chatId = 'CHAT_ID';
$text = "Новая заявка: {$name}, {$phone}";

file_get_contents(
    "https://api.telegram.org/bot{$botToken}/sendMessage?chat_id={$chatId}&text=" . urlencode($text)
);

Если позже понадобится не разовое уведомление, а бот с командами и кнопками, например чтобы менеджер отвечал клиенту прямо из Telegram, это уже отдельная задача под aiogram или похожий фреймворк: там нужен процесс, который постоянно слушает обновления, а не разовый вызов из PHP-скрипта.

Когда вебхук лучше принимать через n8n, а не свой скрипт

Свой PHP-обработчик хорош, когда логика простая и укладывается в десяток строк: записать, проверить, уведомить. Если вебхук должен разойтись сразу в несколько систем, в CRM, в таблицу, в мессенджер и во внешний сервис аналитики, писать это руками дольше, чем собрать сценарий в n8n: нода Webhook принимает POST от Tilda, а дальше данные расходятся по нужным сервисам без кода.

За удобство приходится платить инфраструктурой: n8n нужно где-то развернуть, значит завести отдельный сервер, следить за обновлениями и сертификатом, либо оплачивать облачную версию сервиса. PHP-скрипт в этом смысле проще: он живёт на том же хостинге, что и сам сайт на Tilda, и отдельных расходов на сервер не требует.

Если через вебхук в сценарий попадают контакты клиентов, имя, телефон, почта, храню их на сервере в России, а не в облачном сервисе с зарубежными дата-центрами: для персональных данных это требование 152-ФЗ, а не вопрос удобства.

Способ Нужен ли отдельный сервер Когда выбираю
PHP-обработчик на хостинге сайта Нет, работает на том же хостинге, где лежит сайт на Tilda Логика простая: записать заявку, проверить токен, отправить уведомление
Сценарий в n8n Да, self-hosted версия требует своего сервера, либо нужна подписка облачного сервиса Заявка должна разойтись сразу в несколько сервисов без написания кода
Готовая интеграция Tilda (CRM, почта) Не нужен, всё настраивается в самой Tilda Достаточно передать заявку в CRM или на почту без кастомной обработки

Если разово настраиваю такой сценарий клиенту, автоматизация в n8n у меня стоит от 25 000 ₽, в эту сумму входит сама логика сценария, а не аренда сервера под него.

Условия и возможности Тильды меняются, поэтому перед запуском я уточняю их у самого сервиса.

Частые вопросы

Как проверить, что вебхук Тильды действительно доходит до сервера?

Сразу после того как приёмщик Webhook сохранён в Настройках сайта, Tilda сама отправляет на указанный адрес POST с данными test=test и ждёт от скрипта ответ 200 OK. На своей стороне логирую весь $_POST в файл или отдельную таблицу перед всей остальной обработкой: так сразу видно, доходит ли запрос вообще и какие поля в нём лежат, ещё до того как код начнёт с ним что-то делать.

Почему обработчик не получает данные с формы?

Чаще всего страницу не опубликовали заново после того, как отметили Webhook в меню «Контент» блока с формой: список получателей обновляется только после публикации. Ещё стоит проверить, что адрес скрипта открыт снаружи без пароля и без блокировки в .htaccess, что скрипт ждёт именно POST, а не GET, и что сама заявка вообще успешно отправляется с формы, например обязательные поля заполнены и капча пройдена.

Нужен ли отдельный сервер для приёма вебхука Тильды?

Нет, обычный PHP-скрипт на том же хостинге, где лежит сайт, справляется полностью: Tilda делает один короткий HTTP-запрос, и хостинга с поддержкой PHP и MySQL для этого достаточно. Отдельный сервер понадобится, только если вебхук нужно передать в более тяжёлый инструмент вроде self-hosted n8n или в процесс, который постоянно слушает обновления, например в бота на aiogram.

Как защитить скрипт от чужих запросов на тот же адрес?

Добавляю в сам URL вебхука секретный параметр, например ?token=…, и первым делом на сервере сверяю его значение, прежде чем читать и сохранять тело запроса. Фильтрация по IP-адресам Tilda для этого подходит хуже, потому что адреса серверов платформы нигде не зафиксированы как постоянные.

Есть задача?

Обсудим в мессенджере

Расскажите, что нужно сделать — отвечу в течение 4 часов в рабочее время. Первая консультация бесплатно.

Продолжая пользование настоящим сайтом Вы выражаете своё согласие на обработку Ваших персональных данных (файлов куки) с использованием Yandex.Metrika.
Понятно