將 Webhook 文件丟畀 Devin Desktop,20 分鐘搞掂 LINE 訊息接收服務
Devin Desktop——2026 年初由 Windsurf 更名而嚟,搭載嘅 SWE-1.6 模型輸出速度去到 950 tokens/s——係目前我身邊開發者討論得最多嘅 AI 編碼工具。用法好直接:將參考文件丟畀佢,描述你想要乜嘢,迭代到跑得起為止。我想試吓呢套流程用喺 webhook API 上面效果點。
任務:寫一個 Python 服務,接收 LINE 訊息嘅 webhook 事件,結構化日誌輸出——嗰種細團隊會部署喺訊息佇列或工單系統前面嘅 handler。唔使 LINE 官方帳號、唔使 Messaging API 憑證、唔使管理 channel access token。只要入站訊息以標準化 JSON 嘅形式到達就得。
最終成品
一個 FastAPI 服務(大約 40 行代碼):
- 接收 UnifyPort 統一 webhook 嘅
message.received事件 - 用
signing_secret做 HMAC-SHA256 簽章驗證 - 將每條訊息以結構化 JSON 記錄日誌——provider、sender、text、timestamp
- 所有事件回傳 200,簽章無效回傳 401
耗時:約 20 分鐘。你需要一個 UnifyPort 工作區並連接 LINE 帳號(LINE App 掃碼就得),以及 Python 3.10+。
點解唔直接用 LINE Messaging API?
官方路徑:
- 建立 LINE 官方帳號——需要 LINE Business ID,需要企業或實名個人認證
- 喺 LINE Developers 控制台啟用 Messaging API——設定 channel、生成 channel access token、設定 webhook URL
- 解析 LINE 嘅 webhook payload:事件結構係
{"events": [{"type": "message", "message": {"type": "text", "text": "..."}, "source": {"userId": "U..."}}]}——巢狀嘅、LINE 專有格式 - 驗證簽章:用 channel secret 校驗
x-line-signature——LINE 用嘅係 Base64 編碼嘅 HMAC-SHA256,唔係 hex - 處理 reply token:每個事件帶一個有效期 30 秒嘅
replyToken,遲咗回覆就靜默失敗
代碼跑得起,但淨係跑到 LINE。webhook payload 格式、簽章方式、reply token 機制——冇一樣可以複用去 WhatsApp 或 Telegram。加第二個平台就要由頭開始做第二套整合。
UnifyPort 嘅非官方介面連接個人 LINE 帳號——掃碼連接,唔使官方帳號——將每條入站訊息標準化為 message.received 事件,同 WhatsApp、Telegram、TikTok、Zalo、X 嘅格式一模一樣。一個 handler 覆蓋六個平台。
準備:將 API 文件餵畀 Devin Desktop
開啟 Devin Desktop,建立新工作階段。第一次提問之前,畀佢上下文:
- 貼上 UnifyPort webhook 文件入面嘅
message.received事件 payload:{ "event": "message.received", "account_id": "acct_7kQnWx", "provider": "line", "from": "user_a3f82c", "text": "可以改到星期五嗎?", "timestamp": 1751270400, "message_id": "line_msg_5e9d21" } - 貼上 HMAC-SHA256 簽章驗證部分——
x-unifyport-signatureheader、用signing_secret對原始請求主體計算 hex digest
Devin 會將貼上嘅內容作為工作階段上下文索引。SWE-1.6 Fast 以 950 tok/s 處理,文件消化只需幾秒。Cursor、Claude Code、Copilot 都一樣——貼上或附加就得。工具可以換,文件先係重點。
建構過程
第一個 prompt——handler 骨架:
根據我啱啱貼上嘅 UnifyPort webhook 文件,寫一個 FastAPI 服務,POST /webhook 路由。當事件係 “message.received” 時,用 Python 嘅 logging 模組以結構化 JSON 記錄 provider、from、text 同 timestamp。所有事件回傳 200。用 uvicorn 啟動。
Devin 讀取上下文並生成:
from fastapi import FastAPI, Request
import logging, json
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("inbound")
app = FastAPI()
@app.post("/webhook")
async def webhook(request: Request):
evt = await request.json()
if evt.get("event") == "message.received":
logger.info(json.dumps({
"provider": evt["provider"],
"from": evt["from"],
"text": evt["text"],
"timestamp": evt["timestamp"],
"message_id": evt["message_id"],
}))
return {"status": "ok"}
十二行 handler。冇 LINE 專用 import,冇 linebot SDK,冇 channel access token。事件結構夠扁平,唔使額外解析。
第二個 prompt——簽章驗證:
加上 HMAC-SHA256 簽章驗證。header 係 x-unifyport-signature,secret 從環境變數 UNIFYPORT_SIGNING_SECRET 讀取,HMAC 對原始請求主體 bytes 計算——唔係重新序列化嘅 JSON。驗證失敗回傳 401。用 timing-safe 比較。
第三個 prompt——合併整理:
將簽章驗證合併入 webhook handler。驗證通過之後先將 body 解析為 JSON。加一個 GET /health 健康檢查。加上 uvicorn.run,port 8000。
完整嘅 server.py:
from fastapi import FastAPI, Request, HTTPException
import hmac, hashlib, os, json, logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("inbound")
SIGNING_SECRET = os.environ["UNIFYPORT_SIGNING_SECRET"]
app = FastAPI()
@app.get("/health")
async def health():
return {"status": "ok"}
@app.post("/webhook")
async def webhook(request: Request):
body = await request.body()
sig = request.headers.get("x-unifyport-signature", "")
expected = hmac.new(
SIGNING_SECRET.encode(), body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(sig, expected):
raise HTTPException(status_code=401, detail="invalid signature")
evt = json.loads(body)
if evt.get("event") == "message.received":
logger.info(json.dumps({
"provider": evt["provider"],
"from": evt["from"],
"text": evt["text"],
"timestamp": evt["timestamp"],
"message_id": evt["message_id"],
}))
return {"status": "ok"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
唔到 40 行。簽章驗證、結構化日誌、可以直接部署喺任何反向代理後面。
跑起嚟,睇訊息入嚟
喺 UnifyPort 工作區連接 LINE 帳號——LINE 支援掃碼認證,開啟 LINE App 掃一下就連上。唔使 LINE 官方帳號、唔使 Business ID、唔使設定 Messaging API。
註冊一個 webhook 端點指向你嘅伺服器,設定 subscribed_events: ["message.received"] 同 signing_secret。啟動服務:
UNIFYPORT_SIGNING_SECRET=your_secret python server.py
叫朋友傳一條測試訊息到你嘅 LINE。事件到達:
{
"event": "message.received",
"account_id": "acct_3Xk1wL",
"provider": "line",
"from": "user_a3f82c",
"text": "可以改到星期五嗎?",
"timestamp": 1751270400,
"message_id": "line_msg_5e9d21"
}
伺服器驗證簽章,輸出結構化日誌。如果簽章驗證失敗回傳 401——檢查 UNIFYPORT_SIGNING_SECRET 係咪同 webhook 端點設定嘅一致。
加 WhatsApp,一行代碼都唔使改
喺同一個工作區連接 WhatsApp 帳號,訂閱同一個 webhook 端點。WhatsApp 訊息到達時,格式完全一樣:
{
"event": "message.received",
"account_id": "acct_7kQnWx",
"provider": "whatsapp",
"from": "user_d4f29a",
"text": "訂單確認,星期一出貨",
"timestamp": 1751270460,
"message_id": "wa_msg_8b3e71"
}
同一個 handler,同樣嘅結構化日誌。provider 欄位由 "line" 變成 "whatsapp",代碼路徑完全一致。LINE Messaging API 嘅 handler 要加 WhatsApp 就要由頭開始做一套完全唔同嘅整合——唔同嘅 webhook payload、唔同嘅簽章格式、唔同嘅 SDK。呢個 handler 覆蓋六個平台,因為事件結構唔變。
呢個就係成套流程:將 UnifyPort API 文件貼畀 Devin Desktop,描述你要嘅 handler,迭代到跑得起。工具寫代碼,標準化 webhook 令代碼適用於所有平台。換成 Cursor、Claude Code 或 Copilot 都一樣——文件唔變,handler 唔超過 40 行。