我讓 Claude Code 搭了一個 X 私訊和提及監聽器——完全沒碰 X 的 API — UnifyPort
X 的 API 沒有免費方案。讀取一則私訊收費 $0.015,讀取一則貼文收費 $0.005。如果你是一個兩人團隊,只想知道有人在 X 上傳了私訊或提及了你,官方開發者平台會要求你先儲值、建立專案、等待審核、開啟計量計費——你連一則訊息都還沒處理。
我跳過了這一切。打開 Claude Code,把 UnifyPort 的 webhook 介面文件貼到上下文裡,讓它用 Node.js 搭建一個 X 私訊和提及監聽器。四十分鐘後,我拿到一個 Express 伺服器,能驗證每次交付的簽章、把事件寫入結構化日誌檔、並將告警推送到 Discord 頻道。不需要 X 開發者帳號,不用按次計費,不用排隊審核。
你最終會得到什麼
一個 Node.js Express 伺服器:
- 接收 UnifyPort 統一 webhook 的
message.received事件 - 使用 HMAC-SHA256 和
signing_secret驗證每次交付的簽章 - 把每則 X 訊息寫入
messages.jsonl檔案 - 透過 webhook 向 Discord 頻道發送告警
耗時:不到一小時。你需要一個 UnifyPort 工作區,透過 UnifyPort Exporter 瀏覽器擴充功能連接 X 帳號——一鍵工作階段匯入,無需開發者憑證——以及一個 Discord webhook URL。
準備工作:把文件餵給 Claude Code
在提示之前,先把 API 文件送入代理的上下文。Claude Code 能直接讀檔案,所以在專案根目錄建立 unifyport-reference.md,包含:
message.received事件酬載結構x-unifyport-signature標頭和 HMAC-SHA256 簽章驗證說明POST /v1/webhook-endpoints建立呼叫
也可以把這些內容直接貼到對話中。關鍵點:真實的欄位名稱輸入,正確的程式碼輸出。沒有文件,代理會編造一個 X 專用 SDK 或不存在的 dm.received 事件類型。
Cursor、Windsurf、Copilot 用法相同——透過 @Docs、文件面板或直接貼文件到上下文。工具是次要的,文件是核心。
建構過程:逐條提示
第一個提示——骨架:
讀取 unifyport-reference.md。用 Express 寫一個 server.js,包含 POST /webhook 路由。當 event 是 “message.received” 時,印出 provider、from 和 text 欄位。所有請求回傳 200。
Claude Code 輸出:
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
const evt = req.body;
if (evt.event === "message.received") {
console.log(`[${evt.provider}] ${evt.from}: ${evt.text}`);
}
res.sendStatus(200);
});
app.listen(3000, () => console.log("listening on :3000"));
六行處理器。因為事件結構在六個平台上完全一致,不需要任何 X 專用的解析——evt.provider 顯示 "x",但結構和 WhatsApp 或 Telegram 訊息完全相同。
第二個提示——簽章驗證:
每次交付都包含 x-unifyport-signature 標頭。用環境變數中的 signing_secret 進行 HMAC-SHA256 驗證。HMAC 必須對原始請求本體計算——不能對重新序列化的 JSON 計算。驗證失敗回傳 401。使用時間安全比較。
Claude Code 加上驗證層:
import crypto from "crypto";
const SIGNING_SECRET = process.env.UNIFYPORT_SIGNING_SECRET;
app.use(express.json({
verify: (req, _res, buf) => { req.rawBody = buf; }
}));
function isValid(req) {
const sig = req.get("x-unifyport-signature") || "";
const expected = crypto
.createHmac("sha256", SIGNING_SECRET)
.update(req.rawBody)
.digest("hex");
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
verify 回呼在 Express 解析 JSON 之前捕獲原始 buffer——如果代理用了 req.body 再序列化成 JSON,HMAC 永遠不會匹配。因為提示指定了「原始請求本體」,代理一次就寫對了。
第三個提示——日誌記錄和 Discord 告警:
新增兩個功能:(1) 把每個 message.received 事件附加到 messages.jsonl——每行一個 JSON 物件,包含 timestamp、provider、from、text 和 message_id。(2) 向環境變數 DISCORD_WEBHOOK_URL 指定的 Discord webhook 發送一行告警。
完整的 server.js:
import express from "express";
import crypto from "crypto";
import { appendFileSync } from "fs";
const SIGNING_SECRET = process.env.UNIFYPORT_SIGNING_SECRET;
const DISCORD_WEBHOOK = process.env.DISCORD_WEBHOOK_URL;
const app = express();
app.use(express.json({
verify: (req, _res, buf) => { req.rawBody = buf; }
}));
function isValid(req) {
const sig = req.get("x-unifyport-signature") || "";
const expected = crypto
.createHmac("sha256", SIGNING_SECRET)
.update(req.rawBody)
.digest("hex");
return sig.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}
app.post("/webhook", async (req, res) => {
if (!isValid(req)) return res.sendStatus(401);
const evt = req.body;
if (evt.event === "message.received") {
const record = JSON.stringify({
timestamp: evt.timestamp,
provider: evt.provider,
from: evt.from,
text: evt.text,
message_id: evt.message_id,
});
appendFileSync("messages.jsonl", record + "\n");
if (DISCORD_WEBHOOK) {
await fetch(DISCORD_WEBHOOK, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
content: `**[${evt.provider}]** ${evt.from}: ${evt.text}`,
}),
});
}
}
res.sendStatus(200);
});
app.listen(3000, () => console.log("listening on :3000"));
不到 50 行。簽章驗證、磁碟日誌、Discord 轉發全部就位。處理器不會對 provider 做分支判斷——事件結構相同,不管訊息來自 X、WhatsApp 還是其他平台。
執行並看到 X 訊息到達
在 UnifyPort 控制台連接你的 X 帳號。X 使用 UnifyPort Exporter 瀏覽器擴充功能進行工作階段匯入——點擊擴充功能圖示、授權,幾秒鐘內帳號就連接好了。不需要開發者後台,不需要申請 API 金鑰,不需要審核佇列。
註冊一個 webhook 端點指向你的伺服器,設定 subscribed_events: ["message.received"] 和 signing_secret。啟動伺服器,然後從另一個帳號給你的 X 帳號發一則測試私訊。事件到達:
{
"event": "message.received",
"account_id": "acct_7Kp3mR",
"provider": "x",
"from": "user_9d4f2b",
"text": "Hey, are you still taking freelance projects?",
"timestamp": 1750521600,
"message_id": "x_msg_8c1e5a"
}
你的伺服器驗證簽章、把紀錄附加到 messages.jsonl、並將告警發送到 Discord。如果簽章驗證失敗——401——檢查 UNIFYPORT_SIGNING_SECRET 是否與 webhook 端點上設定的值一致。
擴展:零程式碼改動新增 Telegram
在同一個工作區連接 Telegram 帳號,訂閱同一個 webhook 端點。Telegram 訊息以完全相同的結構到達——不同的 provider 欄位,結構一模一樣:
{
"event": "message.received",
"account_id": "acct_2Xn5wL",
"provider": "telegram",
"from": "user_4a7c8d",
"text": "Can you hop on a call tomorrow?",
"timestamp": 1750521660,
"message_id": "tg_msg_3b9f1e"
}
不需要新的處理器,不需要 Telegram 專用的解析邏輯。messages.jsonl 檔案現在同時包含 X 和 Telegram 事件,使用相同的 schema,Discord 顯示兩個來源的告警。後續新增 WhatsApp、LINE、Zalo 或 TikTok 也是同樣的流程——連接帳號,現有的處理器自動處理一切。
這和直接對接 X API 的差別不僅是成本——而是準入門檻。X 要求通過審核的開發者帳號、儲值的專案和按次計費的承諾。UnifyPort 的工作階段匯入路徑透過瀏覽器連接你的個人 X 帳號,把每則私訊和提及正規化為與其他五個平台完全相同的事件結構。把 Claude Code 指向這個介面——一個事件 schema、一個簽章機制——你就能在午餐前跑起一個帶驗證、日誌、告警的監聽器。然後新增其他所有平台,程式碼一行不改。