Zalo QR 授權:處理 qrcode_expired 並接收簽名 Webhook
如果 Zalo QR 授權回傳 qrcode_expired,不要再叫用戶掃描舊 QR。重新呼叫 POST /v1/accounts/{account_id}/auth/qr/start,再輪詢 POST /v1/accounts/{account_id}/auth/qr/check。同時要先建立 Webhook endpoint,授權狀態同之後的訊息先有地方投遞。帳號授權成功後,Zalo 入站訊息會以簽名的 message.received event 傳到你的服務。
重點
- 在 UnifyPort,Zalo 授權只用 QR:建立 Zalo messaging account 時設定
auth_mode: "qrcode",毋須預先提供 provider credentials。 - Webhook 要放在最前。授權更新同之後的入站訊息都靠事件流傳送。
qrcode_expired是正常重試狀態:重新呼叫qr/start,展示新的 QR 內容,再繼續輪詢。- 解析 JSON 前,先用
X-Device-Timestamp + "." + raw body驗證X-Device-Signature。 - 如果你需要 Zalo Official Account 身份或 OA 原生功能,應評估官方 OA 路線;本文講 UnifyPort 面向既有 messaging account 的非官方介面。
如果你未決定應該用 OA 還是既有帳號,先看 Zalo Official Account API vs personal-account webhook。做東南亞客服時,亦可參考 LINE、Zalo、X 用同一個 Webhook 的分流方式。
這個流程不是官方 OA Webhook
Zalo 官方開發文件有 Official Account API 同 OA Webhook,適合需要 OA 身份、OA 管理後台或官方平台關係的情況。
UnifyPort 的流程不同:用 QR 授權連接一個 Zalo messaging account,再由 UnifyPort Webhook delivery layer 輸出標準化 events。Zalo authorization 說明 Zalo 使用 QR login,並要求 Webhook endpoint 接收授權及訊息事件。
第一步:掃描前先建立簽名 Webhook
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/zalo",
"status": "active",
"subscribed_events": ["account.auth.succeeded", "account.auth.required", "message.received"],
"signing_secret": "zalo-support-2026"
}'
欄位請見 Create webhook endpoint:url 要是 absolute URL,status 可為 active 或 inactive,subscribed_events 可用明確 public event names 或 ["*"]。初次測試建議先用明確 event names。
第二步:建立 Zalo messaging account
curl -X POST https://api.unifyport.ai/v1/accounts \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Zalo Support Inbox",
"provider": "zalo",
"region": "global",
"status": "active",
"auth_mode": "qrcode",
"capabilities": ["receive_message"],
"provider_data": {},
"metadata": { "workflow": "support-intake" }
}'
保存 response 入面的 account_id。之後 QR endpoints 都會用到;不要將正式帳號 ID 放到公開 issue 或 AI 對話。
第三步:啟動 QR 授權並處理 qrcode_expired
curl -X POST "https://api.unifyport.ai/v1/accounts/$ACCOUNT_ID/auth/qr/start" \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
然後輪詢:
curl -X POST "https://api.unifyport.ai/v1/accounts/$ACCOUNT_ID/auth/qr/check" \
-H "X-Api-Key: $UNIFYPORT_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'
如果狀態是 qrcode_expired,棄用舊 QR 畫面,再呼叫 qr/start。後台 UI 最好清楚分成三格:等待掃描、已過期要產生新 QR、已授權。
第四步:驗證簽名後先處理 event
Webhook delivery 定義簽名字串如下:
<X-Device-Timestamp>.<raw request body>
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const signingSecret = process.env.WEBHOOK_SIGNING_SECRET;
app.post('/unifyport/zalo', 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');
if (signature.length !== expected.length) return res.sendStatus(401);
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString('utf8'));
if (event.type === 'message.received' && event.provider === 'zalo') {
// 先儲存 event.id、event.account_id、event.occurred_at、event.data,再做分流。
}
res.sendStatus(202);
});
第五步:儲存標準化 Zalo event
{
"id": "evt_2f9c1a4b7e",
"type": "message.received",
"provider": "zalo",
"account_id": "acc_8c21d0",
"occurred_at": "2026-06-08T12:34:56Z",
"data": {
"conversation": { "id": "5005", "type": "user" },
"sender": { "id": "4004", "type": "user", "name": "Minh Nguyen" },
"message": {
"id": "3003",
"text": "Sản phẩm này còn hàng không?",
"direction": "inbound",
"sent_at": "2026-06-08T12:34:55Z"
}
}
}
先儲存,再分流。Slack、CRM、AI 分類或客服派單都應在 event 已持久化後才執行。通用設計可參考 Webhook-first inbound integration checklist。
FAQ
Zalo 回傳 qrcode_expired 要點做?
重新呼叫 auth/qr/start,展示新的 QR 內容,並繼續輪詢 auth/qr/check。不要重用過期 QR。
呢個流程需要 Zalo developer credentials 嗎?
不需要預先提供 provider credentials。指定用戶掃描 QR 後,系統才識別帳號身份。
這是否 Zalo 官方 OA Webhook?
不是。官方 OA Webhook 屬於 Official Account 開發模型;本文描述 UnifyPort 非官方介面的標準化入站 events。
下一步
並排打開 Zalo authorization 和 Webhook delivery,先連接測試帳號並發一則 Zalo 入站訊息,再接下游自動化。
來源
官方來源核對於 2026-09-04:
令訊息接入變成一條穩定嘅產品管線。
先用統一嘅 API 跑通發送,再用標準事件將所有入站訊息接返去業務系統。