WhatsApp Business Cloud API 設置
Hermes 可以通過 Meta 的官方 WhatsApp Business Cloud API 連接到 WhatsApp。這是生產級別的路徑:沒有 Node.js 橋接子進程,沒有二維碼,沒有賬戶被封禁的風險。
作為交換:
- 你需要一個 Meta Business 賬戶(而非個人 WhatsApp)。
- 機器人運行在專用的商業電話號碼上,而不是你的個人號碼。
- Hermes 網關需要一個公共 HTTPS URL,以便 Meta 通過 webhook 傳遞入站消息。
- 在用戶最後一條消息發出 24 小時後的回覆需要預先批准的模板(這是 Meta 的“客戶服務窗口”規則,而非 Hermes 的限制)。
如果這些約束不適用於你的用例,Baileys 橋接集成 是替代方案——使用個人賬戶,不需要公共 URL,但非官方且容易封號。
- Cloud API(本指南)——運行真正的商業機器人,追求穩定性,可以接受 Meta 驗證和模板文書工作
- Baileys 橋接——個人項目、快速演示、單用戶設置,願意承擔機器人電話號碼賬戶被封的風險
快速開始
hermes whatsapp-cloud
該向導將引導你完成所有憑據的配置,並在你粘貼時驗證每一項(避免最常見的設置陷阱——將電話號碼粘貼到 Phone Number ID 字段中),並打印出需要在嚮導之外執行的部分的確切後續說明(啟動 cloudflared、配置 Meta 的 webhook 儀表板)。
本頁的其餘部分是手動參考文檔。
前提條件
- 一個 Meta Business 賬戶。在 business.facebook.com 創建一個。
- 一個啟用了 WhatsApp 的 Meta 應用。參見下方的“創建 Meta 應用”。
- 一種通過 HTTPS 將本地端口暴露給公共互聯網的方法。推薦使用 Cloudflare Tunnel (
cloudflared)——免費,無需端口轉發,無需域名。ngrok、帶有反向代理 + TLS 的自有域名,或直接綁定到公網 IP 的 VPS 也都可以工作。 - 可選但推薦:在
PATH中安裝 ffmpeg,以便出站語音消息呈現為原生的 WhatsApp 語音筆記氣泡(綠色波形),而不是 MP3 音頻附件。如果缺失,Hermes 會優雅降級。
創建 Meta 應用
- 前往 developers.facebook.com/apps → Create App(創建應用)。
- 選擇用例:"Connect with customers through WhatsApp"(通過 WhatsApp 與客戶聯繫)→ Next(下一步)。
- 選擇或創建一個業務組合。查看發佈要求。確認 → Create app(創建應用)。
- 創建後,你將進入 Customize use case → Connect on WhatsApp → Quickstart(自定義用例 → 連接 WhatsApp → 快速入門)。點擊 Start using the API(開始使用 API)→ 你現在位於 API Setup(API 設置)頁面。
- 確保已鏈接 WhatsApp Business Account (WABA)。如果你在步驟 3 中創建了新的業務組合,系統會自動創建一個。請在 API 設置頁面中驗證。
你需要從儀表板中獲取以下值——嚮導會按此順序提示你輸入:
| 值 | 儀表板中的位置 | 字段格式 | 備註 |
|---|---|---|---|
| Phone Number ID | App Dashboard → WhatsApp → API Setup → "From" 下拉菜單下方 | 數字,15-17 位 | 不是電話號碼本身。最常見的設置錯誤是將實際電話號碼粘貼到這裡。 |
| Access Token | App Dashboard → WhatsApp → API Setup → "Generate access token" | 以 EAA 開頭,100+ 字符 | 臨時令牌有效期為 24 小時——參見下方的“永久令牌”以用於生產環境。 |
| App Secret | App Dashboard → Settings → Basic → 點擊 App secret 旁邊的 "Show" | 32 位小寫十六進制 | 用於驗證傳入的 webhook 簽名。如果沒有它,入站交付將被拒絕並返回 503。 |
| App ID(可選) | App Dashboard → Settings → Basic | 數字,15-16 位 | 消息傳遞不需要,對分析有用。 |
| WABA ID(可選) | App Dashboard → WhatsApp → API Setup → 靠近頂部 | 數字,15+ 位 | 消息傳遞不需要,對分析有用。 |
永久令牌(生產環境)
臨時訪問令牌在 24 小時後過期,這意味著今天生成的令牌明天將停止工作。對於生產部署,請使用 System User 永久令牌:
- 前往 business.facebook.com/latest/settings → System users(系統用戶,左側邊欄)。
- Add(添加)→ 名稱(例如
hermes-bot)→ 角色:Admin(管理員)。 - 選擇新用戶 → Assign Assets(分配資產):
- 選擇你的應用 → 在 Full control(完全控制)下切換 Manage app(管理應用)。
- 選擇你的 WhatsApp 賬戶 → 在 Full control(完全控制)下切換 Manage WhatsApp Business Accounts(管理 WhatsApp Business 賬戶)。
- 點擊 Assign assets(分配資產)。
- 使用以下權限 Generate token(生成令牌):
business_managementwhatsapp_business_messagingwhatsapp_business_management
- 設置 token expiration: Never(令牌過期:永不)。
- 複製令牌 → 更新
~/.hermes/.env中的WHATSAPP_CLOUD_ACCESS_TOKEN→ 重啟網關。
除非你明確撤銷,否則 System User 令牌不會過期。
將 Hermes 暴露給互聯網
Cloud API 通過 HTTPS POST 將入站消息傳遞到你的 webhook URL——這意味著 Hermes 網關必須可以從 Meta 的服務器訪問。三種常見方式:
Cloudflare Tunnel(推薦)
免費,無需端口轉發,適用於 Windows / macOS / Linux。作為獨立進程與網關並行運行。
安裝:
# Windows
winget install Cloudflare.cloudflared
# macOS
brew install cloudflared
# Linux
# Download the binary from https://github.com/cloudflare/cloudflared/releases
運行快速隧道(無需 Cloudflare 賬戶 — 會生成一個 https://<random>.trycloudflare.com URL):
cloudflared tunnel --url http://localhost:8090
記下打印出的 URL — 這就是你要提供給 Meta 的地址。
免費的快速隧道 URL 每次重啟 cloudflared 時都會變化。若要獲得穩定的 URL,請使用 cloudflared tunnel login 登錄並創建命名隧道。免費的 Cloudflare 賬戶可獲得無限數量的命名隧道 — 請參閱 Cloudflare 文檔 瞭解命名隧道的工作流程。
ngrok
ngrok http 8090
免費層級在每次重啟時會顯示不同的 URL。付費層級提供穩定的子域名。
自有域名 + 反向代理
如果你已經擁有一臺帶有 TLS 證書(Caddy、nginx 等)的服務器,請將路由指向 localhost:8090。這是生產環境中最穩定的選項,但需要現有的基礎設施。
在 Meta 側配置 Webhook
隧道運行後:
- 記下隧道打印出的公共 URL — 例如
https://abc123.trycloudflare.com。 - 生成一個 驗證令牌(Verify Token) — 嚮導會使用
secrets.token_urlsafe(32)為你生成;如果是手動配置,請運行:將其保存為python -c "import secrets; print(secrets.token_urlsafe(32))"~/.hermes/.env中的WHATSAPP_CLOUD_VERIFY_TOKEN。 - 啟動 Hermes 網關:
hermes gateway。 - 在 Meta App Dashboard → WhatsApp → Configuration(或根據 UI 版本不同,選擇 Use cases → Customize → Configuration)→ 點擊 Webhook 部分的 Edit。
- 填寫:
- Callback URL:
https://abc123.trycloudflare.com/whatsapp/webhook - Verify Token:步驟 2 中的字符串(必須完全匹配)
- Callback URL:
- 點擊 Verify and save。Meta 會通過 GET 請求訪問你的 URL,網關回顯挑戰值,Meta 隨後將 webhook 標記為已驗證。
- 在 Webhook fields 下,點擊 Manage → 訂閱 messages 字段。這告訴 Meta 實際將入站消息傳遞到你的 webhook。
手動驗證循環(從第三個終端執行):
TUNNEL="https://abc123.trycloudflare.com"
VERIFY="<your verify token>"
# Should print HTTP 200 with body "hello"
curl -i "$TUNNEL/whatsapp/webhook?hub.mode=subscribe&hub.verify_token=$VERIFY&hub.challenge=hello"
# Health endpoint — should show verify_token_configured: true and app_secret_configured: true
curl "$TUNNEL/health"
收件人白名單(Meta 側)
在開發模式下(在你的應用通過應用審核之前),Meta 限制了你的機器人可以發送消息的號碼:
- App Dashboard → WhatsApp → API Setup → To 下拉菜單。
- 點擊 Manage phone number list。
- 添加你想要發送消息的電話號碼(你自己的、團隊的、友好的測試者)。Meta 會通過短信或 WhatsApp 向每個號碼發送一個 6 位數的驗證碼。
開發模式下最多支持 5 個號碼。通過應用審核後,此限制將被移除。
允許列表(Hermes 側)
除了 Meta 的收件人白名單外,Hermes 還有自己的每平臺允許列表,用於控制 代理處理哪些入站消息。添加到 ~/.hermes/.env:
# Comma-separated phone numbers, country code, no '+' / spaces / dashes
WHATSAPP_CLOUD_ALLOWED_USERS=15551234567,15557654321
# Or allow everyone (only safe in combination with Meta's recipient whitelist)
# WHATSAPP_CLOUD_ALLOW_ALL_USERS=true
嚮導會在第 6 步設置此項。如果沒有允許列表,所有入站消息都會被拒絕 — 這是有意為之,以防止在收件人白名單放寬時,機器人被隨機號碼調用。
完善機器人的 WhatsApp 個人資料
WhatsApp 會在聊天標題和聯繫人列表中顯示機器人的 名稱和個人資料圖片。這些無法通過 Cloud API 設置 — 它們位於 Meta 的 Business Manager 中。
一旦你的機器人正常工作,請訪問 business.facebook.com/wa/manage/phone-numbers,點擊你的電話號碼,你將找到:
| 內容 | 位置 | 備註 |
|---|---|---|
| 顯示名稱 | 電話號碼頁面頂部 | 更改需經過 Meta 的名稱審核流程(約 24–48 小時)。 |
| 個人資料圖片 | 電話號碼頁面頂部 | 正方形圖片,建議 ≥640×640px。立即更新。 |
| 關於 / 描述 / 網站 / 電子郵件 / 營業時間 / 類別 | “Edit profile”按鈕 | 當用戶點擊機器人名稱時,這些信息會出現在信息面板中。僅用於展示。 |
| 驗證徽章(綠色對勾) | Business Manager → Security Center → Start Verification | 需要 Meta 單獨的商家驗證流程。 |
hermes whatsapp-cloud 嚮導會在設置結束時打印這些鏈接。這些都不是機器人工作所必需的 — 它們純粹是為了優化機器人在用戶眼中的外觀。
配置參考
所有設置都位於 ~/.hermes/.env 中。必需的值以 粗體 顯示。
| 變量 | 默認值 | 描述 |
|---|---|---|
WHATSAPP_CLOUD_PHONE_NUMBER_ID | — | 來自 API 設置的 15-17 位 ID。不是電話號碼。 |
WHATSAPP_CLOUD_ACCESS_TOKEN | — | Meta 訪問令牌(以 EAA 開頭)。臨時令牌有效期為 24 小時,或使用系統用戶永久令牌。 |
WHATSAPP_CLOUD_APP_SECRET | — | 來自 Settings → Basic 的 32 字符十六進制字符串。如果沒有它,入站請求將被拒絕並返回 503。 |
WHATSAPP_CLOUD_VERIFY_TOKEN | — | 用於 GET 握手的共享密鑰。由嚮導自動生成。 |
WHATSAPP_CLOUD_ALLOWED_USERS | — | 允許向機器人發送消息的 wa_id,以逗號分隔。 |
WHATSAPP_CLOUD_ALLOW_ALL_USERS | false | 設置為 true 以繞過允許列表。 |
WHATSAPP_CLOUD_APP_ID | — | 可選,用於未來的分析集成。 |
WHATSAPP_CLOUD_WABA_ID | — | 可選,用於未來的分析集成。 |
WHATSAPP_CLOUD_WEBHOOK_HOST | 0.0.0.0 | Webhook 服務器綁定的接口。 |
WHATSAPP_CLOUD_WEBHOOK_PORT | 8090 | Webhook 服務器綁定的端口。必須與隧道轉發的端口匹配。 |
WHATSAPP_CLOUD_WEBHOOK_PATH | /whatsapp/webhook | Meta POST 請求的 URL 路徑。 |
WHATSAPP_CLOUD_API_VERSION | v20.0 | Meta Graph API 版本。僅在 Meta 文檔推薦更新版本時才覆蓋此值。 |
WHATSAPP_CLOUD_HOME_CHANNEL | — | 用作機器人主通道(用於 cron 任務等)的 wa_id。 |
你可以同時啟用 Baileys (whatsapp) 和 Cloud (whatsapp_cloud) 適配器,並針對不同的電話號碼。
功能
入站 (Inbound)
- 文本消息 — 直接傳遞給代理。
- 圖片 — 自動下載並附加到代理的輸入中。具有原生視覺能力的模型(Claude、GPT-4o、Gemini 等)直接讀取圖片;非視覺模型接收自動生成的文本描述。
- 語音筆記 — 自動下載為
.ogg格式,通過你配置的 STT 提供商(本地 faster-whisper、OpenAI/Nous、Groq 等)進行轉錄,然後作為文本交給代理。 - 文檔 — 自動下載。小型可讀文本文件(
.txt、.md、.json、.py、.csv等),最大 100KB,會被內聯到代理的輸入中,以便其無需調用工具即可讀取。較大的文件會在本地緩存,供代理的其他工具訪問。 - 按鈕點擊 — 當用戶點擊機器人之前發送的按鈕(澄清選擇、命令批准、斜槓命令確認)時,點擊事件會直接路由到正確的處理程序。過期的點擊會回退為被視為常規文本輸入。
- 回覆上下文 — 當用戶回覆之前的機器人消息時,代理會將原始消息視為上下文。
出站 (Outbound)
- 文本 — Markdown 會自動轉換為 WhatsApp 風格的語法(
**bold**→*bold*,~~strike~~→~strike~,標題 → 粗體,[link](url)→link (url))。長消息會以每塊 4096 個字符進行分割。 - 圖片 — 支持代理生成的圖片和本地圖片文件,作為原生照片附件發送。
- 語音消息 — 文本轉語音 (TTS) 輸出通過 ffmpeg 轉換為原生的 WhatsApp 語音筆記氣泡(綠色波形)。如果未安裝 ffmpeg,則回退為 MP3 音頻附件。請參閱下方的“語音消息”。
- 視頻 / 文檔 — 均受支持,作為原生附件發送。
交互式用戶體驗 (Interactive UX)
當代理調用以下任何流程時,Hermes 會使用 WhatsApp 的原生交互式消息——使用點擊即答按鈕,而不是“回覆數字”提示:
clarify工具 — 多項選擇題呈現為快速回覆按鈕(1–3 個選項)或點擊打開的列表面板(4 個及以上選項)。選擇“✏️ Other”允許用戶輸入自由形式的答案,代理將其接收為最終結果。- 危險命令批准 — 當代理的終端/代碼執行遇到受限命令時,用戶會看到
✅ Approve/❌ Deny按鈕,而無需輸入/approve或/deny。 - 斜槓命令確認 — 特權命令如
/reload-mcp會顯示✅ Approve Once/🔒 Always/❌ Cancel按鈕。
如果按鈕無法渲染(例如在舊版 WhatsApp 客戶端上),所有交互式提示都會優雅地降級為純文本。
已讀回執和輸入指示器
Hermes 會立即確認入站消息:
- 一旦網關收到消息,你的消息就會顯示藍色雙勾。
- 當代理準備回覆時,你在 WhatsApp 聊天中的機器人名稱會顯示**“typing…”**(正在輸入…)。
- 當機器人的第一條響應消息到達時,輸入指示器會自動消失。
這使得用戶可以清楚地知道機器人是已經看到了你的消息,還是仍在處理響應。
語音消息
WhatsApp 區分“語音筆記”(綠色波形氣泡)和通用音頻文件附件。區別僅在於編解碼器:語音筆記需要是使用 opus 編碼的 audio/ogg 格式。
Hermes TTS 生成 MP3 格式。有兩種路徑:
- PATH 中包含 ffmpeg(推薦)— 外發 TTS 會被轉換並以標準的語音消息形式送達。安裝方法:
- Windows:
winget install Gyan.FFmpeg - macOS:
brew install ffmpeg - Linux:使用包管理器
- Windows:
- 不包含 ffmpeg — 外發 TTS 會以 MP3 音頻附件形式送達。播放正常,只是看起來不像語音消息。網關日誌中會觸發一次警告,以便你知曉。
你可以通過健康檢查端點確認網關是否找到了 ffmpeg:
curl http://localhost:8090/health
# look for "ffmpeg_present": true
已知限制
24 小時對話窗口
Meta 僅允許在用戶最後一條 inbound 消息後的 24 小時窗口內發送自由格式消息。超出該窗口後,Meta 的 API 僅接受預批准的消息模板。
實際影響:
- 響應式聊天(用戶私信 → 機器人在 24 小時內回覆 → 用戶回覆 → ...)可以永久持續。這涵蓋了 >95% 的常規機器人使用場景。
- 間隔超過 24 小時後向 WhatsApp 發送消息的 Cron 任務將失敗,並返回 Graph 錯誤代碼
131047(“Re-engagement message”)。 - 耗時超過 24 小時的長期運行的
delegate_task異步結果也會以相同方式失敗。 - 將外部事件路由到 WhatsApp 的 Webhook 訂閱者在用戶最近未私信機器人時會失敗。
Hermes 會在其系統提示中告知代理此窗口限制,因此模型在安排延遲消息時知道要提及這一點。
消息模板支持(用於窗口外發送的變通方案)尚未在 Hermes 中實現。如果你需要此功能,請 提交 issue — 該功能已在計劃中,但需等待明確的需求信號。
群聊
Cloud API 對群組的支持有限(能力層級由 Meta 控制)。Hermes 的 whatsapp_cloud 適配器在 v1 版本中目前僅處理直接消息。如果你需要群聊功能,請使用 Baileys 橋接器。
外發速率限制
Meta 的默認吞吐量為每個商業電話號碼 80 條消息/秒,並提供升級選項。Hermes 目前未在客戶端強制執行此限制 — 極高量的發送可能會觸及 Meta 的限制。
故障排除
Meta 儀表板中的設置驗證失敗(“URL couldn't be validated”)
幾乎總是以下原因之一:
- 隧道 URL 錯誤或已過期 — cloudflared 快速隧道會輪換。獲取新的 URL 並更新
.env和 Meta 儀表板。 - 驗證令牌不匹配 —
~/.hermes/.env中的WHATSAPP_CLOUD_VERIFY_TOKEN必須與你在 Meta 儀表板中輸入的內容完全一致。先運行上述 curl 探測命令,確認網關的驗證握手在本地正常工作。 - 網關未運行 — 檢查
hermes gateway是否正在運行。 - 未設置 App Secret — 如果沒有設置,Hermes 會以 503 拒絕 inbound POST 請求。Meta 將其解釋為“無法驗證”。
graph error 100: Object with ID '...' does not exist
你將電話號碼(10-11 位數字)粘貼到了 WHATSAPP_CLOUD_PHONE_NUMBER_ID 中,而不是電話號碼 ID(Meta 的 15-17 位內部 ID)。重新檢查 API 設置頁面 — 電話號碼 ID 顯示在“From”下拉菜單下方。
嚮導現在會通過驗證器捕獲此錯誤,但如果你手動配置,瞭解這一點很有幫助。
graph error 190: Authentication Error
你的訪問令牌無效。子代碼:
subcode 463— 令牌已過期。臨時令牌有效期為 24 小時。重新生成,或切換到系統用戶永久令牌(見上文)。subcode 467— 令牌已失效(被撤銷或密碼已更改)。- 其他 190 — 生成令牌時未包含所需的權限。確保選中了所有三個權限(
business_management、whatsapp_business_messaging、whatsapp_business_management)。
graph error 131047: Re-engagement message
24 小時對話窗口已過期(參見“已知限制”)。你可以:
- 要求用戶先私信機器人以重新打開窗口。
- 等待 Hermes 實現模板支持。
Inbound message: media metadata fetch failed (status=401)
與外發相同的 401 根本原因(graph error 190)— 訪問令牌無效或已過期。修復令牌即可。
機器人回覆顯示為原始 JSON / 工具調用洩露
常見原因:為 whatsapp_cloud 配置的工具集缺少代理想要調用的工具。檢查 hermes tools list 並驗證平臺是否正在使用 hermes-whatsapp(默認的 Cloud 適配器工具集,與 Baileys 相同)。
如果模型發出類似工具調用的文本而不是結構化調用,通常意味著工具集實際上為空。請參閱 hermes_cli/platforms.py 瞭解平臺到默認工具集的映射。
STT(語音消息轉錄)返回空值 / “could not transcribe”
默認的 stt.provider: local 需要 pip install faster-whisper。如果你是 Nous 訂閱用戶,可以通過 Meta 的託管音頻網關路由 STT:
hermes config set stt.provider openai
hermes config set stt.use_gateway true
hermes gateway restart
這使用你的 Nous Portal 訪問令牌,而無需單獨的 OpenAI 密鑰。
安全說明
- 將 App Secret 視為密碼 — 任何擁有它的人都可以偽造 Hermes 會接受為真實的有效 webhook 負載。
- verify token 是一個共享密鑰 — 洩露的風險較低(最壞的情況是有人可以將 Meta 的 webhook 重新訂閱到他們的其他 URL),但仍應避免將其提交到代碼庫中。
- access token 是你的機器人身份 — System User 令牌等同於長期有效的 API 密鑰。如果部署遭到入侵,請立即輪換。
- 當設置
WHATSAPP_CLOUD_APP_SECRET時,webhook 端點僅接受簽名請求 — 即使在開發環境中也要保持設置。如果沒有它,網關將拒絕入站交付並返回 HTTP 503。 /health端點未經身份驗證 — 暴露它是安全的,因為它只報告配置存在的布爾值,而不報告值本身。但如果你不想暴露它,可以在反向代理/隧道層限制訪問。
與 Baileys 橋接的比較
Baileys (hermes whatsapp) | Cloud API (hermes whatsapp-cloud) | |
|---|---|---|
| 賬戶類型 | 個人 | 商業 |
| 設置 | 掃描二維碼 | Meta 應用 + WABA + 令牌 |
| 依賴項 | Node.js + npm | 純 Python (httpx + aiohttp) |
| 進程 | 託管的 Node 子進程 | aiohttp webhook 服務器 |
| 需要公共 URL? | 否 | 是 |
| 賬戶封禁風險 | 是(非官方 API) | 否(官方支持) |
| 入站 | 輪詢 Node 橋接 | 來自 Meta 的 Webhook POST |
| 出站 | 本地橋接 → Baileys | HTTPS 到 graph.facebook.com |
| 群組 | 完全支持 | 僅限私聊(v1) |
| 24小時窗口 | 無限制 | 硬性規定 — 之後需要模板消息 |
| 語音筆記(出站) | 原生支持 | 原生支持需 ffmpeg,否則回退到 MP3 |
| 已讀回執 | 否 | 是(藍色雙勾) |
| 輸入指示器 | 否 | 是(響應時自動消失) |
| 交互式按鈕 | 僅文本回退 | 原生支持(澄清、批准、斜槓確認) |
| 生產環境使用 | 有風險(Meta 可能封禁) | 為此設計 |
大多數為個人項目運行 Hermes 的用戶更喜歡 Baileys。大多數運行面向客戶的機器人的用戶更喜歡 Cloud API。
另請參閱
- Meta 官方 WhatsApp Business Cloud API 文檔 — 底層平臺、定價、應用審核和 Meta 側速率限制的權威參考。
- WhatsApp (Baileys 橋接) 設置 — 個人項目的替代集成方案。
- 消息平臺概覽 — 所有消息集成一覽。