Xây dựng n8n WhatsApp AI Agent từ inbound webhook có chữ ký
Cách nhanh nhất để xây dựng WhatsApp AI Agent trong năm 2026 thường không phải là bắt đầu bằng agent. Hãy bắt đầu từ inbound edge.
Nỗi đau này rất dễ thấy trong cộng đồng. Trong một thread n8n trên Reddit gần đây, một builder muốn tự động hóa WhatsApp với DeepSeek, xử lý media, chạy ổn định trong production, nhưng không muốn mắc kẹt ở Meta Business verification và Cloud API setup. Các thread khác cũng nói về việc WhatsApp trigger chỉ chạy một lần, chỉ chạy ở test mode, hoặc webhook delivery và workflow response không khớp thời điểm.
Với đội ngũ nhỏ, thứ tự đúng là: nhận tin nhắn một cách đáng tin cậy, trả acknowledgement thật nhanh, lưu event, rồi mới để AI Agent quyết định có trả lời hay không.
UnifyPort cung cấp phần inbound bằng event message.received có chữ ký. n8n cung cấp workflow canvas. Đặt thêm một edge verifier nhỏ ở giữa, bạn có một đường đi phù hợp production:
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
Ở Việt Nam, Zalo cũng quan trọng như WhatsApp trong nhiều kịch bản chăm sóc khách hàng. Điểm mạnh của cách này là bạn có thể bắt đầu với WhatsApp hôm nay và thêm Zalo sau đó mà không phải viết lại toàn bộ inbound workflow.
Vì sao n8n webhook URL quan trọng
Tài liệu chính thức Webhook node của n8n nói rõ rằng một Webhook node có hai URL: test URL và production URL. Test URL dùng cho manual run khi editor đang listen. Production URL là URL dùng sau khi workflow đã active.
Với customer-message pipeline, hãy thiết kế quanh production URL. Khách hàng sẽ không gửi lại tin nhắn chỉ vì editor của bạn không listen. Inbound path cần active, ổn định và trả 2xx nhanh.
Respond to Webhook node của n8n hữu ích khi workflow cần tự kiểm soát HTTP response. Với inbound messaging, response nên đơn giản: nhận event, enqueue hoặc lưu trữ, và trả 200. AI reasoning dài, ghi CRM, và outbound reply nên chạy sau khi delivery đã được acknowledge.
Đăng ký UnifyPort webhook
Tạo webhook endpoint trong UnifyPort và subscribe message.received. Đặt signing_secret để mỗi delivery có X-Device-Timestamp và 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 trên không trỏ trực tiếp đến n8n. Nó trỏ đến một edge verifier nhỏ. Cách này giữ signature verification chặt chẽ vì UnifyPort ký raw request body bằng HMAC-SHA256. Chuỗi được ký là:
<X-Device-Timestamp>.<raw request body>
Nếu n8n deployment của bạn có thể lấy đúng raw request bytes trước khi JSON parsing, bạn có thể verify trong n8n. Nhiều team chọn verify bằng một service nhỏ rồi forward trusted event đến n8n production webhook với internal token để ranh giới rõ ràng hơn.
Thêm edge verifier
Đây là verifier đầy đủ bằng Node.js. Nó verify chữ ký UnifyPort, parse event, check event type, và forward trusted payload đến 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);
Service này không lưu credentials của WhatsApp account và không quyết định agent nên trả lời thế nào. Nhiệm vụ duy nhất của nó là chứng minh event đến từ UnifyPort endpoint của bạn và đưa trusted event vào n8n.
Xây dựng n8n workflow
Trong n8n, tạo một active workflow với Webhook trigger dùng production URL. JSON nhận vào đã là standard UnifyPort event:
{
"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 đầu tiên nên có năm node:
- Webhook: nhận event đã forward.
- IF: xác nhận
typelàmessage.receivedvàproviderlàwhatsapp. - Data store, Postgres, Airtable hoặc CRM: lưu
id,account_id,provider,data.conversation.id,data.sender.id, vàdata.message.text. - AI Agent hoặc HTTP Request đến model gateway: phân loại message thành sales, support, billing, hoặc human handoff.
- HTTP Request: tùy chọn trả lời qua UnifyPort.
Hãy lưu trữ trước. Tài liệu webhook của UnifyPort xem events là bản ghi của inbound traffic. Không có message-history read API để lấy lại missed payloads, vì vậy workflow nên persist event trước khi một AI step chậm có thể fail.
Chỉ trả lời sau khi workflow quyết định
Nếu agent cần trả lời, dùng POST /v1/messages. Lấy recipient từ inbound event và giữ reply là một action rõ ràng.
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."
}
}'
Trong n8n, đây là HTTP Request node. Map account_id từ {{$json.account_id}}, recipient id từ {{$json.data.sender.id}}, và message.text từ output của AI node.
Vì sao không nên để agent làm first hop
AI Agent không nên là hệ thống đầu tiên chạm vào customer message. Hệ thống đầu tiên nên đơn giản: verify, acknowledge, store, route. Như vậy operational contract vẫn ổn định kể cả khi model, prompt, hoặc escalation policy thay đổi.
Cấu trúc này cũng giúp cùng một n8n workflow mở rộng ra ngoài WhatsApp. Envelope dùng provider, account_id, occurred_at, và data. Khi bạn kết nối Telegram, LINE, Zalo, TikTok, hoặc X, workflow có thể branch theo provider mà không cần học sáu webhook formats.
WhatsApp Business Developer Hub chính thức vẫn là nơi đúng để học Meta Cloud API, webhooks, pricing, và policy surface. Hãy dùng nó khi bạn build trên official platform. Nhưng nếu team cần inbound WhatsApp support agent trong n8n mà không muốn mang mọi official setup step vào workflow, unofficial interface của UnifyPort giúp thu hẹp bài toán: nhận customer messages có chữ ký và đưa vào những tool team đang dùng.
Hãy làm edge ổn định trước. Khi edge đáng tin cậy, agent chỉ còn là node tiếp theo.