← 所有文章
教學

用簽名入站 Webhook 建立 n8n WhatsApp AI Agent

2026 年想快速做一個 WhatsApp AI Agent,通常唔應該先由 Agent 開始,而係先做好入站邊界。

公開社群入面嘅痛點好直接。最近一則 n8n Reddit 討論入面,有開發者想將 WhatsApp 自動化接到 DeepSeek,希望支援媒體、穩定運行,同時唔想卡喺 Meta Business verification 同 Cloud API 設定流程。其他討論亦經常提到 WhatsApp trigger 只觸發一次、只喺 test mode 生效,或者 webhook delivery 同 workflow response 時機未對齊。

小團隊要先修正嘅係順序:可靠接收訊息,快速確認,先儲存,再畀 AI Agent 決定要唔要回覆。

UnifyPort 提供入站部分:簽名嘅 message.received 事件。n8n 提供 workflow canvas。中間加一個細小嘅邊緣驗證器,就可以得到一條適合正式環境嘅路徑:

WhatsApp 客戶訊息
  -> UnifyPort 簽名 message.received webhook
  -> 驗證 X-Device-Signature 嘅邊緣服務
  -> n8n production Webhook URL
  -> AI 分流、CRM 查詢、Slack 通知,或者透過 POST /v1/messages 回覆

點解 n8n webhook URL 好重要

n8n 官方 Webhook node 文件講得好清楚,一個 Webhook node 有兩個 URL:test URL 同 production URL。test URL 用於 editor 正在 listen 時手動測試;production URL 先係 workflow 啟用後應該接入外部系統嘅地址。

客戶訊息管道一定要圍繞 production URL 設計。客戶唔會因為你個 editor 未 listen 就再發一次訊息。入站路徑應該保持啟用、穩定,並且可以盡快回傳 2xx。

n8n 嘅 Respond to Webhook node 適合由 workflow 自己控制 HTTP response。對入站訊息嚟講,response 應該簡單:接受事件、入 queue 或儲存、回傳 200。長時間 AI 推理、CRM 寫入同出站回覆,都應該喺 delivery 被確認之後先做。

註冊 UnifyPort webhook

喺 UnifyPort 建立 webhook endpoint,並訂閱 message.received。設定 signing_secret,每次投遞就會帶上 X-Device-TimestampX-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 URL,而係填一個細小邊緣驗證器。咁樣可以嚴格做簽名驗證,因為 UnifyPort 使用 HMAC-SHA256 對原始 request body 簽名。被簽名嘅字串係:

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

如果你嘅 n8n 部署可以喺 JSON parse 之前攞到完全一致嘅原始請求 bytes,都可以喺 n8n 內驗證。更多團隊會選擇喺一個小服務驗證,再用內部 token 將可信事件轉發到 n8n production webhook,令邊界更清晰。

加入邊緣驗證器

以下係完整 Node.js 驗證器。佢會驗證 UnifyPort 簽名,解析事件,確認事件類型,並將可信 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);

呢個服務唔保存 WhatsApp 帳號憑證,亦唔決定 Agent 應該點答。佢唯一職責係證明事件來自你嘅 UnifyPort endpoint,然後將可信事件交畀 n8n。

建立 n8n workflow

喺 n8n 入面建立一個已啟用 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 可以有五個節點:

  1. Webhook:接收轉發後嘅事件。
  2. IF:確認 typemessage.received,而且 providerwhatsapp
  3. Data store、Postgres、Airtable 或 CRM:保存 idaccount_idproviderdata.conversation.iddata.sender.iddata.message.text
  4. AI Agent 或指向模型 gateway 嘅 HTTP Request:將訊息分類為銷售、客服、帳單或人工接手。
  5. HTTP Request:按需要透過 UnifyPort 回覆。

先儲存。UnifyPort webhook 文件將事件視為入站流量嘅記錄來源。錯過嘅 payload 無 message-history read API 可以補取,所以 workflow 應該喺慢速 AI 步驟失敗之前先持久化事件。

只喺 workflow 決定後回覆

如果 Agent 需要回覆,使用 POST /v1/messages。收件人來自入站事件,回覆動作保持清晰。

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}},收件人 id 映射做 {{$json.data.sender.id}}message.text 使用 AI 節點輸出。

點解唔應該畀 Agent 做第一個入口

AI Agent 唔應該成為第一個接觸客戶訊息嘅系統。第一個系統應該夠簡單:驗證、確認、儲存、路由。咁即使模型、prompt 或升級規則改變,營運契約仍然穩定。

呢個結構亦可以令同一個 n8n workflow 擴展到 WhatsApp 之外。標準 envelope 使用 provideraccount_idoccurred_atdata。之後接入 Telegram、LINE、Zalo、TikTok 或 X 時,workflow 可以按 provider 分支,而唔需要學六套 webhook 格式。

官方 WhatsApp Business Developer Hub 仍然係學 Meta Cloud API、webhooks、pricing 同 policy surface 嘅正確入口。如果你要建構官方平台能力,就應該參考佢。但如果團隊需要將 WhatsApp 入站客服 Agent 接到 n8n,又唔想將所有官方設定步驟塞入 workflow,UnifyPort 嘅非官方接口會將任務收窄成一件事:接收簽名客戶訊息,交畀團隊已經用緊嘅工具。

先做好邊緣。邊緣可靠之後,Agent 只係另一個節點。