Sau khi tạo UnifyPort API key: checklist kiểm tra Webhook đầu tiên
Sau khi có UnifyPort API key đầu tiên, đừng vội kết nối messaging account ngay. Thứ tự an toàn hơn là: kiểm tra key bằng GET /v1/workspace, tạo signed webhook endpoint, subscribe message.received hoặc ["*"], lưu event khi nhận được, rồi mới authorize WhatsApp, Telegram, LINE, TikTok, Zalo hoặc X. Với đội ngũ ở Việt Nam, cách này đặc biệt hữu ích khi bạn cần nhận cả WhatsApp và Zalo trong cùng một hàng đợi.
Điểm chính
- API key xác thực qua header
X-Api-Key; không đặt trong browser code và không commit vào repository. - Secret đầy đủ của key mới chỉ được trả về một lần trong field
api_key; các list response sau đó chỉ hiển thịkey_prefix. - Nên tạo webhook trước account authorization, vì tiến trình authorization và inbound messages đều đến qua webhook events.
- Bật
signing_secretvà xác thựcX-Device-Signaturebằng raw request body trước khi tin payload. - Hãy xem
message.receivedlà production contract đầu tiên, không phải event demo tạm thời.
Nếu bạn đã có live key và cần thay thế, hãy dùng zero-downtime API key rotation runbook. Nếu bạn đang thiết kế inbound architecture từ đầu, hãy đọc cùng webhook-first integration checklist.
1. Xác nhận key thuộc workspace nào
UnifyPort hiện khả dụng cho một nhóm khách hàng được chọn; tài liệu công khai hướng dẫn liên hệ team để lấy workspace access và API key đầu tiên. Sau khi có key, request đầu tiên nên là kiểm tra workspace dạng read-only, không phải gửi message.
export UNIFYPORT_API_KEY="set-this-in-your-secret-manager"
curl https://api.unifyport.ai/v1/workspace \
-H "X-Api-Key: $UNIFYPORT_API_KEY"
Response thành công xác nhận key map tới một workspace. Introduction docs cũng nêu rằng mọi /v1 endpoint xác thực bằng X-Api-Key request header, và JSON success/error response có top-level request_id để hỗ trợ debug và reconciliation.
2. Tạo key có tên và lưu secret đầy đủ một lần
Nếu workspace cho phép tạo thêm key, hãy đặt tên thể hiện runtime sử dụng nó, ví dụ production inbound worker. Theo Create API key reference, record của key nằm trong key, còn secret đầy đủ chỉ được trả về một lần trong api_key.
curl -X POST https://api.unifyport.ai/v1/api-keys \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Production inbound worker",
"prefix": "dk_live"
}'
Quy tắc vận hành: đưa api_key vừa nhận vào secrets manager ngay, không dán vào issue, chat log hoặc client-side environment variable. OWASP Secrets Management Cheat Sheet chính thức cũng xem API keys là secrets và quản lý tạo, lưu trữ, rotation, revocation, auditing như một lifecycle thống nhất.
3. Register webhook trước khi kết nối account
Hãy làm bước này trước QR, code hoặc session authorization. UnifyPort không đảm bảo replay đầy đủ các webhook delivery đã bỏ lỡ, vì vậy record bền vững của inbound traffic nên nằm trong receiver và database của bạn.
export WEBHOOK_SIGNING_SECRET="generate-a-long-random-secret"
curl -X POST https://api.unifyport.ai/v1/webhook-endpoints \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://inbox.example.com/unifyport/webhook",
"status": "active",
"subscribed_events": ["message.received"],
"signing_secret": "'"$WEBHOOK_SIGNING_SECRET"'"
}'
Create webhook endpoint reference cho phép dùng public standard event names chính xác hoặc ["*"] để nhận toàn bộ public standard events. Nếu bạn xây account state machine đầy đủ, dùng ["*"]; nếu milestone đầu tiên là nhận inbound messages từ WhatsApp hoặc Zalo, bắt đầu với message.received sẽ dễ kiểm tra hơn.
4. Xác thực webhook signature bằng raw body
Delivery docs định nghĩa các header quan trọng: X-Device-Event-Id, X-Device-Delivery-Id, X-Device-Timestamp và X-Device-Signature. Signature là hex-encoded HMAC-SHA256 của:
<X-Device-Timestamp> + "." + <raw request body>
Điểm quan trọng là raw body. Nếu framework parse JSON trước rồi serialize lại, bytes có thể thay đổi và signature verification sẽ fail.
import crypto from 'crypto';
import express from 'express';
const app = express();
const signingSecret = process.env.WEBHOOK_SIGNING_SECRET;
app.post('/unifyport/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const timestamp = req.get('X-Device-Timestamp') || '';
const signature = req.get('X-Device-Signature') || '';
const expected = crypto
.createHmac('sha256', signingSecret)
.update(timestamp + '.')
.update(req.body)
.digest('hex');
const valid = signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!valid) return res.status(401).end();
const event = JSON.parse(req.body.toString('utf8'));
if (event.type === 'message.received') {
console.log(event.provider, event.data.conversation.id, event.data.message.text);
}
res.status(200).end();
});
Tham khảo sâu hơn tại Webhook delivery & signature verification. Trang này cũng giải thích retries, idempotency, stale timestamp checks và quy tắc rằng bất kỳ 2xx response nào cũng xác nhận delivery.
5. Lưu message.received envelope làm contract đầu tiên
Một inbound message thông thường có envelope ổn định gồm id, type, provider, account_id, occurred_at và data. standard event payload reference cho thấy những field nên dùng để thiết kế model:
{
"id": "evt_2f9c1a4b7e",
"type": "message.received",
"provider": "zalo",
"account_id": "acc_8c21d0",
"occurred_at": "2026-06-08T12:34:56Z",
"data": {
"conversation": { "id": "zalo_user_8842", "type": "user" },
"sender": { "id": "zalo_user_8842", "type": "user", "name": "Jordan Lee" },
"message": {
"id": "msg_10472",
"text": "Đơn hàng của tôi đã gửi chưa?",
"direction": "inbound",
"sent_at": "2026-06-08T12:34:55Z"
}
}
}
Lưu top-level event id cho idempotency, provider và account_id cho routing, data.conversation.id cho queue grouping, data.sender.id cho identity, và data.message.id cho message-level actions. Khi shape này đã ổn định, cùng một receiver có thể nhận Zalo hoặc WhatsApp trước, rồi thêm LINE, Telegram, TikTok hoặc X sau. Nếu muốn xem phiên bản có AI coding agent hỗ trợ tạo implementation, đọc AI coding agent auto-reply bot tutorial.
Lỗi thường gặp trong ngày đầu
| Lỗi | Tác hại | Cách an toàn hơn |
|---|---|---|
| Tạo account trước | Auth events có thể đến trước khi receiver sẵn sàng | Tạo webhook endpoint trước |
| Tắt signing | Người biết URL có thể gửi JSON trông giống thật | Đặt signing_secret và xác thực raw-body HMAC |
| Deduplicate theo delivery attempt | Retry có thể gửi lại cùng một event | Deduplicate bằng X-Device-Event-Id hoặc event id |
| Ghi API key vào logs | Secrets lan sang hệ thống khó audit hằng ngày | Lưu trong secrets manager và redact trong logs |
Xem message.received là WhatsApp-only | Đây là normalized event cho các providers được hỗ trợ | Lưu provider/account fields thay vì giả định một platform |
FAQ
Có thể lấy lại API key đầy đủ sau này không?
Không. Create response trả secret đầy đủ một lần trong api_key. List và detail responses chỉ trả metadata an toàn để hiển thị như key_prefix, không trả lại secret đầy đủ.
Nên subscribe message.received hay ["*"]?
Dùng message.received cho inbound test đầu tiên gọn nhất. Dùng ["*"] nếu một receiver cần xử lý auth, runtime, message, receipt, conversation hoặc group events.
Có cần webhook endpoint trước khi tạo account không?
Để first run đáng tin cậy, nên có. Account authorization progress và live inbound messages được gửi qua webhook events, và UnifyPort không hứa replay đầy đủ các payload đã bỏ lỡ.
Có cần official business account trên mọi platform không?
Không. UnifyPort cung cấp unofficial interface cho WhatsApp, Telegram, LINE, TikTok, Zalo và X, đồng thời có thể kết nối personal hoặc ordinary messaging accounts trong mô hình phù hợp.
Bước tiếp theo
Mở Quickstart, lưu API key trong secrets manager, tạo webhook endpoint trước và dùng delivery verification docs làm chuẩn cho receiver implementation.
Sources checked on 2026-09-01
Biến tích hợp nhắn tin thành một pipeline sản phẩm ổn định.
Bắt đầu bằng cách gửi qua một API, rồi đưa mọi tin nhắn inbound trở lại hệ thống kinh doanh bằng sự kiện chuẩn.