Webhook в n8n - адрес, на который другая программа отправляет данные и запускает workflow. В этой инструкции вы отправите учебный JSON с компьютера, проверите два поля и получите собственный ответ. Это основа для приёма заявок и запуска AI-сценариев, но сам webhook не является ИИ-агентом.
Результат инструкции
Рабочая цепочка состоит из пяти узлов: Webhook → Validate Input → Build Reply → Respond OK. При неверных данных Validate Input переключает выполнение на Respond Invalid. Правильный запрос получает HTTP 200 и три поля: status, request_id, message. Неверный - HTTP 422 и объяснение ошибки. Никаких писем, списаний и записей в CRM здесь нет.
Пример рассчитан на локальный n8n и PowerShell в Windows. Для n8n Cloud логика узлов такая же, но адрес берётся из вашего облачного экземпляра. Бесплатного локального запуска достаточно: аккаунт нейросети и API-ключ не нужны.
Что понадобится
- Запущенный локальный n8n с доступом в редактор. Если его ещё нет, сначала установите по инструкции ниже.
- PowerShell, curl.exe и любой текстовый редактор. Команды запускайте на том же компьютере, где открыт локальный n8n.
- Отдельный пустой workflow. Не вставляйте пример поверх рабочей схемы и не используйте настоящие клиентские данные.
Установить n8n локально через Docker
Шаг 1. Скачайте готовую схему
Скачать workflow n8n-webhook-json-demo.json
Сохраните JSON на компьютер. Если браузер показывает содержимое, сохраните страницу как файл с расширением .json. Это учебная схема без credentials, ключей и внешних запросов. Файл не содержит ID существующего workflow и не включает публикацию автоматически. Перед импортом всё равно проверьте, что работаете в новой схеме.
Шаг 2. Создайте новый workflow и вставьте узлы
Откройте Overview → Create workflow. Откройте скачанный JSON в текстовом редакторе, выделите всё и скопируйте. В пустом редакторе n8n щёлкните свободную область схемы и нажмите Ctrl+V. Если в меню More actions есть Import from File, можно выбрать тот же файл вместо вставки.
Должно появиться пять узлов с названием workflow ezgpt-webhook-json-demo. Нажмите Zoom to Fit, если часть узлов ушла за экран. Проверьте соединения: true у Validate Input ведёт к Build Reply, false - к Respond Invalid. Если узлы не появились, не продолжайте на пустом полотне: проверьте, что скопировали весь JSON, а фокус не остался в поле имени.
Шаг 3. Проверьте метод, путь и режим ответа
Откройте сам узел Webhook двойным щелчком по его значку. На вкладке Parameters должны быть HTTP Method = POST, Path = ezgpt-json-demo и Respond = Using 'Respond to Webhook' Node. Authentication = None допустимо только для этого учебного примера на localhost, не для открытого адреса в интернете.
Если такой путь уже занят другим workflow, выберите уникальный, например ezgpt-json-demo-2, и используйте его во всех последующих URL. Нельзя зарегистрировать одну и ту же комбинацию метода и пути для двух работающих схем. Случайное имя пути не заменяет авторизацию.
Шаг 4. Различите Test URL и Production URL
| Адрес | Когда работает | Как проверять |
|---|---|---|
| /webhook-test/ezgpt-json-demo | При ожидании тестового события | Запустить Execute workflow, затем POST |
| /webhook/ezgpt-json-demo | После публикации workflow | Отправить POST, открыть Executions |
В панели Webhook есть переключатель этих адресов. Домен и порт должны вести именно к вашему экземпляру. Ниже используется http://localhost:5679 - замените его на адрес, по которому вы действительно открываете n8n. Если редактор на 5679, а узел показывает 5678, для локального запроса используйте доступный с компьютера порт 5679, сохранив путь.
Такое несовпадение бывает при перенаправлении порта Docker. В полноценном серверном развёртывании оператор настраивает внешний адрес webhook, а не просит клиентов вручную угадывать порт. Не меняйте настройки существующего сервера ради этого теста.
n8n: внешний адрес Webhook за reverse proxy
Шаг 5. Проверьте обязательные поля
Откройте Validate Input - это узел If. Условие должно иметь тип Boolean и оператор is true. В левом значении выберите Expression. В импортированной схеме выражение уже вставлено:
={{ typeof $json.body?.request_id === 'string' && $json.body.request_id.trim().length > 0 && $json.body.request_id.trim().length <= 80 && typeof $json.body?.message === 'string' && $json.body.message.trim().length > 0 && $json.body.message.trim().length <= 1000 }}
Выражение принимает только строки: request_id не пустой и длиной до 80, message не пустой и длиной до 1000 после удаления пробелов по краям. Это простая проверка двух полей, а не полноценная проверка JSON Schema. Число вместо строки, пропущенное поле и строка из пробелов уходят в ветку false. Длина считается JavaScript-свойством length: некоторые emoji занимают больше одной единицы.
Данные из JSON находятся в $json.body. $json.query относится к параметрам URL, а не к телу POST. Не заменяйте body на query, чтобы случайно прошёл один тест: это изменит договорённость о входных данных.
Шаг 6. Проверьте сборку успешного ответа
Откройте Build Reply - это Edit Fields (Set) в режиме Manual Mapping. В нём ровно три строковых поля. status имеет фиксированное значение received. request_id и message - выражения ниже. Include Other Input Fields выключен: заголовки запроса и лишние данные не должны попадать в ответ.
status: received (Fixed, String)
request_id: {{ $json.body.request_id.trim() }} (Expression, String)
message: {{ $json.body.message.trim() }} (Expression, String)
Не собирайте ответ конкатенацией сырого JSON с пользовательским текстом. Здесь n8n формирует объект из отдельных полей, поэтому кавычки и переносы строки внутри message не ломают JSON.
Шаг 7. Проверьте две ветки ответа
В Respond OK установлено Respond With = First Incoming Item, а в Options - Response Code = 200. Узел возвращает объект, собранный в Build Reply. В Respond Invalid установлено Respond With = JSON и Response Code = 422. Его Response Body:
{"status":"rejected","error":"request_id must be a nonempty string up to 80 characters; message must be a nonempty string up to 1000 characters"}
Не соединяйте обе ветки с двумя последовательными ответами: один запрос должен закончиться одним Respond to Webhook. Код 200 сам по себе ещё не доказывает успех - проверяйте тело. Если ответный узел не выполняется, n8n может вернуть стандартный ответ вместо вашего JSON.
Шаг 8. Подготовьте учебный запрос
Создайте на компьютере отдельную папку для теста и откройте в ней PowerShell. Следующая команда создаёт payload.json в этой папке в UTF-8 без BOM. Не запускайте её там, где уже есть важный файл с таким именем.
$payload = '{"request_id":"demo-001","message":"Hello webhook"}'
[IO.File]::WriteAllText((Join-Path (Get-Location) 'payload.json'), $payload, [Text.UTF8Encoding]::new($false))
Файл содержит только вымышленные данные. Использование файла снимает часть проблем с кавычками командной строки Windows. Здесь нужен именно curl.exe, а не сокращение curl, которое в некоторых версиях PowerShell обозначает другую команду.
Шаг 9. Запустите всю цепочку и отправьте POST
Закройте панель узла и нажмите Execute workflow внизу редактора. Дождитесь Waiting for trigger event. Затем выполните команду в PowerShell. При другом адресе n8n замените localhost:5679.
curl.exe --include --max-time 15 --request POST "http://localhost:5679/webhook-test/ezgpt-json-demo" --header "Content-Type: application/json" --data-binary "@payload.json"
В начале ответа ожидается HTTP 200, а ниже - объект:
{"status":"received","request_id":"demo-001","message":"Hello webhook"}
В редакторе должны выполниться Webhook, Validate Input, Build Reply и Respond OK. Respond Invalid не должен выполняться. Если вы нажали только Listen for test event внутри Webhook, проверяется сам триггер: можно получить его данные, но не собственный ответ всей цепочки. Для этого результата используйте Execute workflow.
Тестовое ожидание ограничено по времени; документация описывает окно 120 секунд. После его завершения или для следующей ручной проверки запустите Execute workflow снова. Если получили 404, сначала проверьте ожидание, метод POST и точный путь, а не переписывайте выражения.
n8n: тестовый и рабочий режим Webhook
Шаг 10. Проверьте отказ на неверные данные
Перезапишите только учебный payload.json следующим содержимым. Затем снова нажмите Execute workflow и повторите ту же curl.exe-команду из шага 9.
$payload = '{"request_id":"demo-002"}'
[IO.File]::WriteAllText((Join-Path (Get-Location) 'payload.json'), $payload, [Text.UTF8Encoding]::new($false))
Ожидается HTTP 422 и status = rejected: message отсутствует. В схеме работает ветка false и Respond Invalid; Build Reply не выполняется. Это намеренный отказ вашей проверки, не авария n8n.
Дополнительно попробуйте message из пробелов и числовой request_id - оба должны получить 422. Верните исходный правильный пример: он снова должен получить 200. Если неверный запрос получил received, посмотрите Input и Output Validate Input и убедитесь, что не оставили закреплённые тестовые данные через Pin data.
Шаг 11. Опубликуйте workflow и проверьте рабочий URL
Верните правильный payload.json командой из шага 8. Нажмите Publish в верхней части редактора, при появлении окна оставьте или укажите имя версии и подтвердите Publish. Дождитесь Published. В n8n 2.x обычное сохранение черновика не равно публикации; изменения должны попасть в опубликованную версию.
curl.exe --include --max-time 15 --request POST "http://localhost:5679/webhook/ezgpt-json-demo" --header "Content-Type: application/json" --data-binary "@payload.json"
Ответ должен содержать HTTP 200 и прежние три поля. Для этого адреса не нужно нажимать Execute workflow. Во вкладке Executions откройте новое выполнение, сверив время, request_id и ветку узлов. Повторите плохой пример: ожидается 422. В нашем примере выполнение отклонённого запроса может быть отмечено успешным, потому что схема штатно вернула отказ; это не означает принятие данных.
Шаг 12. Зафиксируйте результат и завершите тест
- Правильный POST получает 200 и status = received. В ответе нет headers, query и других входных полей.
- POST без message получает 422 и status = rejected. Build Reply не запускается.
- Кавычки, русский текст и перенос строки сохраняются в значении message без поломки JSON.
- Test URL без запущенного ожидания получает 404, а опубликованный Production URL работает без ручного запуска.
Сохраните workflow. Если пример больше не нужен, откройте меню рядом с Published и выберите Unpublish: это отключит рабочий webhook, но сохранит схему. Повторная отправка на его Production URL после снятия публикации должна получить 404. Не удаляйте другие workflows и не останавливайте общий n8n.
Если результат отличается
| Симптом | Вероятная причина | Что проверить |
|---|---|---|
| 404 на Test URL | Нет текущего ожидания | Execute workflow, POST и путь |
| 404 на Production URL | Не опубликовано или неверный адрес | Published, порт, путь и метод |
| 422 с rejected | Данные не прошли проверку | Строковые поля request_id и message |
| 200 без нужного JSON | Тестировался только триггер или нет ответной ветки | Полный запуск и Respond to Webhook |
| Соединение не установлено | Неверный порт или n8n остановлен | Адрес редактора и Docker Desktop |
| Ответ не отражает правки | В работе предыдущая публикация | Повторная Publish и новое выполнение |
Если клиент ждёт слишком долго, не увеличивайте тайм-аут бесконечно: проверьте, дошло ли выполнение до ответного узла. Параметр --max-time 15 ограничивает ожидание curl, а не гарантирует остановку workflow. Не повторяйте платёж или отправку письма по этой схеме без защиты от дублей.
Перед подключением сайта или AI-агента
Оставляйте Authentication = None только в локальном упражнении, доступном на вашем компьютере. Перед внешним подключением нужны HTTPS, проверка отправителя (например, Header Auth через credentials), ограничение доступа и нагрузки, а также согласованный формат данных. CORS не является авторизацией. В эту инструкцию открытие доступа извне не входит.
localhost относится к компьютеру, который выполняет запрос. Сайт в интернете, n8n Cloud и приложение в другом контейнере не могут обратиться к вашему n8n по своему localhost. Для реальной интеграции нужен корректно развёрнутый доступный адрес; не выставляйте учебный порт в интернет без защиты.
request_id в примере - метка для проверки, не защита от повторов. Каждый одинаковый POST запускает новое выполнение. Если добавите CRM, рассылку, публикацию или платный вызов модели, сначала настройте хранение обработанных идентификаторов, обработку повторов и ручное подтверждение опасных действий. Наш workflow ничего из этого не делает.
Что проверено редакцией
8 октября 2026 года пример проверен на локальном n8n 2.42.4. В редакторе создан отдельный workflow, выполнен полный ручной запуск и публикация. Через Production URL прошли восемь HTTP-проверок: обычный JSON, русский текст с кавычками и переносом строки, пропущенное поле, неверный тип, пробелы, превышение длины и два граничных случая. Правильные данные возвращали 200, отклонённые - 422. Test URL без ожидания и запрос неверным методом возвращали 404. n8n Cloud, внешний сервер, авторизацию внешнего отправителя и платные модели не тестировали. Обложка - редакционная иллюстрация, не снимок интерфейса.
Частые вопросы
Почему webhook n8n возвращает 404?
Для Test URL запустите Execute workflow и отправьте POST во время ожидания. Для Production URL нужна опубликованная версия workflow. В обоих случаях проверьте порт, точный путь и метод. Открытие ссылки браузером отправляет GET, а в примере настроен POST.
Почему приходит 200, но нет моего JSON?
Проверьте, что запустили весь workflow, а не только Listen for test event внутри Webhook. В Webhook должен быть режим ответа через Respond to Webhook; успешная ветка должна дойти до Respond OK. Сверяйте тело ответа, а не только HTTP-код.
Где искать поля отправленного JSON в n8n?
Для нашего запроса с Content-Type: application/json данные находятся в $json.body. Параметры URL находятся в $json.query. Нужны строковые request_id и message. Другие типы содержимого следует проверять отдельно, а не считать совместимыми с этим примером.
Можно ли отправить запрос с сайта на localhost?
Внешний сайт или облачный сервис не увидит ваш локальный n8n по своему localhost. Нужен доступный защищённый серверный адрес или собственный безопасный способ связи. В упражнении запрос отправляется с того же компьютера, где работает n8n.
Можно ли сразу добавить к webhook ИИ-агента?
Сначала добейтесь проверенного приёма данных и ответа без модели. Затем добавляйте AI-узел после проверки входа, отдельно проверяя тайм-ауты, расходы и ошибки. Webhook сам по себе не является ИИ-агентом; request_id в этом примере не предотвращает повторное выполнение.