一個 LINE Webhook 搞定全日本團隊:福岡新創如何將 LINE 訊息分流至 Slack、CRM 與 AI
週二早上九點四十七分,大阪的一位客戶透過 LINE 傳訊息給他的業務經理:「CSV 匯出一直失敗——這是已知問題嗎?」那位業務經理正在開會,訊息在她的手機上躺了三個小時。等她回覆時,客戶早已透過官網提交了支援工單——還在 X 上標記了公司,質問到底有沒有人在監控他們的 LINE 頻道。
這不是平台限制的問題。LINE 本身作為通訊軟體運作得很好。問題在於,福岡辦公室的六個人各自在自己的 LINE 帳號上接收客戶訊息,用著自己的手機,對於誰在回覆什麼,完全沒有共同的視野。這家公司是一個 B2B SaaS 團隊,銷售物流規劃工具給日本及東南亞各地的倉儲業者——他們早已過了「每個人自己顧自己的 LINE」就能應付客服的階段。但所有替代方案似乎都要求客戶離開 LINE,而在日本,這根本行不通。
那個不存在的佇列
這支團隊在 2026 年初的支援架構是這樣的:三位業務代表和兩位支援工程師各自擁有一個 LINE 帳號,客戶把他們加為好友。訊息送達各自的手機,沒有共用收件匣、沒有回覆追蹤、沒有 SLA。如果有人請病假,他們的訊息就躺在那裡直到人回來才會被看到。如果客戶在晚上七點之後傳訊息,就得等到下一個工作天——不是團隊不想幫忙,而是沒有人知道訊息進來了。
公司曾考慮過 LINE 官方帳號(OA)的方案,它提供共用收件匣和部分自動化功能。但 OA 的申請流程需要長達 60 個工作天的驗證,而未驗證等級的好友上限是 500 人——對於客戶群已接近 800 人的團隊來說,這是個硬性的天花板。已驗證和進階等級可以解鎖更高的上限,但伴隨月費以及互動窗口規則,規範商家何時可以主動聯繫。這支團隊不會主動聯繫客戶,他們只負責回覆。OA 的群發機制解決的是他們根本不存在的問題。
與此同時,維持現狀的營運成本不斷攀升。2026 年第一季,團隊記錄了 23 次客戶訊息超過四小時未被回覆的事件,其中七件導致客戶透過其他管道升級了支援工單,兩件引發了 X 上的公開抱怨。支援主管 Kenji 開始用試算表追蹤漏回的訊息,但在第六週後就放棄更新了。
一個 Webhook,三個目的地
轉捩點不是什麼危機——而是公司 CTO 在 Slack 上的一則訊息,他一直在研究基於 webhook 的訊息分流機制。概念很簡單:與其讓每個人各自查看自己的 LINE,不如透過一個統一介面串接全部六個 LINE 帳號,將收到的訊息轉發到團隊已經在用的工具上。Slack 用來即時掌握狀況,CRM 用來記錄和追蹤,而針對常見問題,則由 AI 產生回覆草稿供團隊審核後再送出。
團隊用 QR Code 驗證將 LINE 帳號連接到 UnifyPort——這是 LINE 在該平台上唯一支援的驗證方式。每個帳號掃描大約花 30 秒,不到一小時,六個帳號全部上線,單一 webhook 端點以 message.received 事件接收所有進站的 LINE 訊息。
Webhook 的 payload 長這樣:
{
"id": "evt_9a3f7c2e01",
"type": "message.received",
"provider": "line",
"account_id": "acc_4b82d1",
"occurred_at": "2026-05-12T01:47:23Z",
"data": {
"conversation": {
"id": "U4af2c891...",
"type": "user",
"title": "Tanaka-san"
},
"sender": {
"id": "U4af2c891...",
"type": "user",
"name": "Tanaka-san"
},
"message": {
"id": "msg_18420...",
"type": "text",
"text": "The CSV export keeps failing — is this a known issue?",
"direction": "inbound",
"sent_at": "2026-05-12T01:47:22Z"
},
"event": {
"kind": "message_received"
}
}
}
每次推送都會附帶一個 X-Device-Signature 標頭——這是將時間戳記與原始請求內體串接後,用 webhook 的 signing_secret 進行 HMAC-SHA256 簽章所產生的十六進位摘要。團隊的 Express 處理器會在處理任何邏輯之前先驗證簽章:
import crypto from 'crypto';
import express from 'express';
const app = express();
const SECRET = process.env.WEBHOOK_SIGNING_SECRET;
app.post('/webhook', 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', SECRET);
hmac.update(timestamp + '.');
hmac.update(req.body);
const expected = hmac.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
return res.status(401).end();
}
const event = JSON.parse(req.body.toString('utf8'));
if (event.type === 'message.received') {
await routeMessage(event);
}
res.status(200).end();
});
有意思的不是 webhook 處理器本身——每個整合都有這東西。真正關鍵的是驗證通過後執行的 routeMessage 函式。分流邏輯並非把所有訊息丟進同一個佇列,而是根據訊息內容和對話情境來判斷它該去哪裡。
分流邏輯:Slack、CRM、AI——或三者全部
團隊的分流規則在前兩週不斷演進,最終版本分為三個層級:
第一層——Slack 通知(每則訊息)。 每則進站的 LINE 訊息都會發佈到 Slack 的 #support-line 頻道,附上發送者名稱、訊息預覽,以及 account_id,讓團隊知道是哪位業務的帳號收到的。光是這點就解決了「訊息躺在某人手機上」的問題。如果帳號擁有者正在開會,團隊中任何人都可以在 Slack 上看到這則訊息,並透過 UnifyPort 的 POST /v1/messages 端點,使用原始訊息中的 reply_to.reply_token 進行回覆。
第二層——CRM 記錄(每則訊息)。 一個平行呼叫會在 CRM 中建立或更新聯絡人紀錄,包含完整訊息文字、時間戳記和對話 ID。在此之前,客戶在 LINE 上的互動對 CRM 來說是看不見的——它們只存在於手機上的個別聊天紀錄中。現在,每段 LINE 對話都有了完整的稽核軌跡,與電子郵件和網站工單的歷史並列在一起。
第三層——AI 草稿(僅限常見問題)。 一個簡單的關鍵字分類器會將進站訊息與常見主題清單進行比對:CSV 匯出、帳單、登入問題、API 文件需求。如果找到匹配項,訊息會被轉發到內部的 LLM 端點,並附帶包含相關文件段落的系統提示。AI 的回覆草稿會發佈到 #support-drafts Slack 頻道,附帶一個「審核並傳送」按鈕。沒有經過人工核准的回覆不會被送出——但草稿幾秒內就準備好了,業務代表只需點一下。
async function routeMessage(event) {
const { conversation, sender, message } = event.data;
const accountId = event.account_id;
// Tier 1: Always notify Slack
await postToSlack('#support-line', {
account: accountId,
sender: sender.name,
preview: message.text?.slice(0, 120),
reply_token: message.reply_token,
});
// Tier 2: Always log to CRM
await crm.upsertContact({
external_id: sender.id,
platform: 'line',
name: sender.name,
last_message: message.text,
last_message_at: message.sent_at,
});
// Tier 3: AI draft for routine questions
const topic = classifyTopic(message.text);
if (topic) {
const draft = await generateDraft(topic, message.text, sender.name);
await postToSlack('#support-drafts', {
sender: sender.name,
topic,
draft,
account_id: accountId,
reply_token: message.reply_token,
});
}
}
classifyTopic 函式刻意保持簡單——用的是關鍵字對應表,而非神經網路分類器。「CSV」、「export」、「download」對應到匯出文件主題。「請求」、「料金」、「支払い」對應到帳單主題。維持基於規則的設計意味著團隊可以在幾分鐘內——而非幾小時——除錯分流錯誤。
用對話標籤落實團隊當責
團隊在第二週採用了 UnifyPort 的對話標籤功能。他們透過 POST /v1/conversations/labels 端點,為每位成員建立標籤:kenji、yuki、hiro、sales。訊息進來時,分流函式會為對話標上帳號擁有者的標籤。如果帳號擁有者不在辦公室(透過簡單的日曆整合來確認),對話會被重新標記給值班人員。
這意味著在任何時刻,任何團隊成員都可以呼叫 GET /v1/conversations/labels,精確查看哪些對話被分配給自己——跨越全部六個 LINE 帳號。共用收件匣的問題並非透過建立新的收件匣來解決,而是在既有的多個帳號上為對話加上標籤。
標籤也驅動了每週報告:一個排程任務會拉取所有被標上每位業務標籤的對話,計算回覆時間(從 message.received 的 occurred_at 到第一次出站 POST /v1/messages 呼叫的時間差),並在每週一早上將摘要發佈到 #support-metrics。
第一週 vs 第四週
數據說明了一切。在 webhook 上線前一週,團隊在 LINE 上的中位回覆時間是 3 小時 40 分鐘,有 11 則訊息超過四小時未被回覆。到了第四週,中位回覆時間縮短至 22 分鐘,零則訊息超過四小時未回覆——最長的一次是 1 小時 15 分鐘,發生在全公司外出活動期間。
AI 草稿層級處理了大約 35% 的進站訊息。團隊核准並直接送出約 80% 的草稿,無需修改。剩餘 20% 需要小幅改寫——通常是因為客戶的問題有關鍵字分類器遺漏的細微之處。即使在這些情況下,草稿也給了業務代表一個起點,將撰寫時間從幾分鐘縮短到幾秒鐘。
CRM 整合帶來了一個意想不到的附加效果:業務團隊開始利用 LINE 對話紀錄來準備續約電話。在 webhook 之前,業務代表在進入續約會議時,完全沒有客戶過去在 LINE 上的支援互動紀錄。現在他們可以看到每一則訊息、每一次回覆時間和每一個解決方案——全部自動記錄。
團隊沒有改變的事
客戶完全沒有察覺任何差異。他們仍然向使用了數月的同一批 LINE 帳號傳訊息,仍然收到同一批人的回覆。唯一的差別是回覆變快了,而且如果他們慣常的業務代表不在,會有其他人接手——因為訊息對整個團隊在 Slack 上都是可見的,而不是埋在某一個人的手機裡。
團隊也繼續將 LINE 帳號維持為個人帳號,而非 OA 帳號。UnifyPort 的 webhook 不論帳號類型都會推送進站訊息——OA 驗證佇列和互動窗口屬於出站群發的範疇,而這支團隊的工作流程完全是進站。如果哪天他們決定要進行主動行銷(季節性促銷、產品公告),OA 方案就會變得有意義。在此之前,那只是一層不需要的行政流程。
這個模式
這不只是一個 LINE 的故事。任何在多個個人帳號上接收客戶訊息的團隊——無論是在 WhatsApp、Telegram、X 還是 Zalo——都面臨同樣的分流問題。Webhook 不在乎訊息來自哪個平台;provider 欄位會改變,但 payload 結構、HMAC-SHA256 驗證和分流邏輯完全相同。這支福岡團隊已經在規劃將他們的 WhatsApp 帳號(東南亞倉儲合作夥伴使用的)納入同一套分流系統。一個處理器、一組標籤、一條指標管线。
如果你團隊的客服策略是「每個人自己顧自己的訊息」,那問題不在於你是否需要更好的平台——而在於你的訊息是否需要更好的分流層。一個 webhook 端點、20 行分流邏輯,加上你已經在用的工具,可能就夠了。