← Все статьи
Руководство

Как собрать n8n WhatsApp AI Agent на подписанном inbound webhook

Самый быстрый путь к WhatsApp AI Agent в 2026 году обычно начинается не с агента. Сначала нужно сделать надежный inbound edge.

Проблема хорошо видна в открытых сообществах. В недавнем обсуждении n8n на Reddit разработчик хотел автоматизировать WhatsApp через DeepSeek, поддерживать media, получить production stability и при этом не застрять на Meta Business verification и Cloud API setup. В других обсуждениях люди отлаживают похожие симптомы: WhatsApp trigger срабатывает один раз, работает только в test mode или ломается из-за несогласованности webhook delivery и workflow response.

Для небольшой команды правильный порядок такой: надежно принять сообщение, быстро подтвердить доставку, сохранить событие и только потом дать AI Agent решить, нужно ли отвечать.

UnifyPort дает inbound-часть как подписанное событие message.received. n8n дает визуальный workflow. Между ними стоит поставить маленький edge verifier:

WhatsApp customer message
  -> UnifyPort signed message.received webhook
  -> Edge verifier for X-Device-Signature
  -> n8n production Webhook URL
  -> AI triage, CRM lookup, Slack alert, or reply via POST /v1/messages

Почему важен n8n webhook URL

Официальная документация n8n Webhook node говорит, что у Webhook node есть два URL: test URL и production URL. Test URL нужен для ручных запусков, пока editor слушает события. Production URL используется после того, как workflow активирован.

Для customer-message pipeline нужно проектировать именно production URL. Клиент не будет повторно отправлять сообщение только потому, что ваш editor не слушал test URL. Inbound path должен быть активным, стабильным и быстро возвращать 2xx.

n8n Respond to Webhook node полезен, когда workflow сам управляет HTTP response. Для inbound messaging response должен быть простым: принять событие, поставить его в очередь или сохранить, вернуть 200. Долгое AI reasoning, запись в CRM и outbound replies лучше выполнять после acknowledgement.

Зарегистрируйте UnifyPort webhook

Создайте webhook endpoint в UnifyPort и подпишитесь на message.received. Укажите signing_secret, чтобы каждая доставка содержала X-Device-Timestamp и X-Device-Signature.

curl -X POST https://api.unifyport.ai/v1/webhook-endpoints \
  -H "X-Api-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://edge.example.com/unifyport/n8n",
  "status": "active",
  "subscribed_events": ["message.received"],
  "signing_secret": "<WEBHOOK_SIGNING_SECRET>"
}'

Этот URL ведет не прямо в n8n, а в маленький edge verifier. Так проще строго проверять подпись, потому что UnifyPort подписывает raw request body через HMAC-SHA256. Строка для подписи выглядит так:

<X-Device-Timestamp>.<raw request body>

Если ваша n8n deployment может предоставить точные raw bytes до JSON parsing, проверку можно сделать внутри n8n. Но для большинства команд чище держать проверку в маленьком сервисе и пересылать в n8n production webhook только trusted events с internal token.

Добавьте edge verifier

Ниже полный Node.js verifier. Он проверяет подпись UnifyPort, парсит событие, проверяет тип и пересылает trusted payload в n8n.

import crypto from "crypto";
import express from "express";

const app = express();
const signingSecret = process.env.WEBHOOK_SIGNING_SECRET;
const n8nWebhookUrl = process.env.N8N_PRODUCTION_WEBHOOK_URL;
const internalToken = process.env.N8N_INTERNAL_TOKEN;

app.post("/unifyport/n8n", express.raw({ type: "application/json" }), async (req, res) => {
  const timestamp = req.get("X-Device-Timestamp") || "";
  const signature = req.get("X-Device-Signature") || "";

  const hmac = crypto.createHmac("sha256", signingSecret);
  hmac.update(timestamp);
  hmac.update(".");
  hmac.update(req.body);
  const expected = hmac.digest("hex");

  const valid =
    signature.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

  if (!valid) {
    res.status(401).end();
    return;
  }

  const event = JSON.parse(req.body.toString("utf8"));
  if (event.type !== "message.received") {
    res.status(202).end();
    return;
  }

  await fetch(n8nWebhookUrl, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Internal-Token": internalToken
    },
    body: JSON.stringify(event)
  });

  res.status(200).end();
});

app.listen(3000);

Этот сервис не хранит credentials от WhatsApp account и не решает, как должен отвечать agent. Его единственная задача — доказать, что событие пришло от вашего UnifyPort endpoint, и передать trusted event в n8n.

Соберите n8n workflow

В n8n создайте active workflow с Webhook trigger и production URL. Входящий JSON уже имеет стандартную форму UnifyPort:

{
  "id": "evt_2f9c1a4b7e",
  "type": "message.received",
  "provider": "whatsapp",
  "account_id": "acc_8c21d0",
  "occurred_at": "2026-07-08T02:30:00Z",
  "data": {
    "conversation": { "id": "8613912345678", "type": "user", "title": "Jordan Lee" },
    "sender": { "id": "8613912345678", "name": "Jordan Lee", "type": "user" },
    "message": {
      "id": "wamid.HBgM",
      "type": "text",
      "text": "Can I change the delivery address?",
      "direction": "inbound",
      "sent_at": "2026-07-08T02:29:59Z"
    },
    "event": { "kind": "message_received" }
  }
}

Практичный первый workflow состоит из пяти nodes:

  1. Webhook: получает forwarded event.
  2. IF: проверяет, что type равен message.received, а provider равен whatsapp.
  3. Data store, Postgres, Airtable или CRM: сохраняет id, account_id, provider, data.conversation.id, data.sender.id и data.message.text.
  4. AI Agent или HTTP Request к model gateway: классифицирует сообщение как sales, support, billing или human handoff.
  5. HTTP Request: при необходимости отвечает через UnifyPort.

Сначала сохраняйте событие. В документации UnifyPort webhook events являются записью inbound traffic. Нет message-history read API, который позволит восстановить пропущенные payloads, поэтому workflow должен сохранить event до медленного AI step.

Отвечайте только после решения workflow

Если agent должен ответить, используйте POST /v1/messages. Получателя берите из inbound event, а reply держите явным действием.

curl -X POST https://api.unifyport.ai/v1/messages \
  -H "X-Api-Key: <YOUR_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
  "account_id": "acc_8c21d0",
  "to": { "id": "8613912345678", "type": "user" },
  "message": {
    "type": "text",
    "text": "Yes. Send us the new delivery address and we will update the order note."
  }
}'

В n8n это HTTP Request node. account_id мапится из {{$json.account_id}}, recipient id из {{$json.data.sender.id}}, а message.text из output AI node.

Почему agent не должен быть первым hop

AI Agent не должен быть первой системой, которая касается customer message. Первой системой должен быть скучный слой: verify, acknowledge, store, route. Так операционный контракт остается стабильным, даже если model, prompt или escalation policy меняются.

Такая структура также помогает расширить тот же n8n workflow за пределы WhatsApp. Envelope использует provider, account_id, occurred_at и data. Когда вы подключите Telegram, LINE, Zalo, TikTok или X, workflow сможет ветвиться по provider, не изучая шесть разных webhook formats.

Официальный WhatsApp Business Developer Hub остается правильным местом для изучения Meta Cloud API, webhooks, pricing и policy surface. Используйте его, если строите поверх официальной platform. Но если вашей команде нужен inbound WhatsApp support agent в n8n без переноса всех официальных setup steps в workflow, unofficial interface UnifyPort сужает задачу: принять подписанное customer message и передать его инструментам, которыми команда уже пользуется.

Сначала сделайте надежный edge. Когда edge надежен, agent становится просто следующим node.