Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


WhatsApp Business Cloud API 设置指南

Hermes 可通过 Meta 的官方WhatsApp Business Cloud API 与 WhatsApp 进行连接。这是生产级解决方案:无需 Node.js 中间进程,无需二维码,也不会存在账号被封的风险。

但相应地,您需要满足以下条件:

  • 您必须拥有 Meta 商业账户(而非个人 WhatsApp 账号);
  • 机器人将运行在专用的企业电话号码上,而非您的个人号码;
  • Hermes 网关需要一个公开的 HTTPS 地址,以便 Meta 通过 webhook 发送消息;
  • 若在用户最后发送消息 24 小时后才回复,则必须使用预先审批好的模板(这是 Meta 的“客户服务时间窗口”规定,并非 Hermes 的限制)。
如果这些要求不符合您的使用场景,Baileys 中间件集成方案 是另一种选择——可使用个人账号,无需公开地址,但属于非官方方案,且更容易导致账号被封。

::提示 我该选哪种方案?

  • Cloud API(本指南所述方式)——用于运行真正的企业级机器人,追求稳定性,愿意接受 Meta 的验证流程及模板审批手续;
  • Baileys 中间件——适用于个人项目、快速演示或单用户场景,但需承担机器人所在电话号码被封的风险。 :::

快速入门

hermes whatsapp-cloud

向导会逐步引导您填写每一项凭证,在您输入时实时验证每一项(从而避免最常见的设置错误——将电话号码误填入“电话号码ID”字段),并针对那些需要在向导之外完成的操作(如启动 Cloudflare Tunnel、配置 Meta 的 webhook 控制面板)提供精确的后续操作指南。

本页面的其余部分则为手动参考资料。


先决条件

  1. 一个 Meta 商家账户。请在 business.facebook.com 上创建。
  2. 一个已启用 WhatsApp 功能的 Meta 应用。详情请参见下文的“创建 Meta 应用”部分。
  3. 一种能够通过 HTTPS 将本地端口暴露到公共互联网的方法。推荐使用 Cloudflare Tunnel(cloudflared)——免费、无需端口转发、也不需要域名。ngrok、带有反向代理和 TLS 的自建域名,或是将网关直接绑定到公网 IP 的 VPS 也同样适用。
  4. 非必需但推荐:确保系统中包含位于 PATH 路径下的 ffmpeg,这样发送的语音消息就会以 WhatsApp 原生的语音气泡形式(绿色波形)呈现,而非 MP3 音频附件。若未安装 ffmpeg,Hermes 仍可正常运行,只是功能会有所受限。

创建 Meta 应用

  1. 访问 developers.facebook.com/apps,然后选择创建应用。
  2. 选择使用场景:“通过 WhatsApp 与客户建立联系”,接着点击下一步。
  3. 选择一个现有的业务组合或创建一个新的。仔细阅读发布要求,确认后点击创建应用。
  4. 创建完成后,您将进入自定义使用场景 → 通过 WhatsApp 建立联系 → 快速入门页面。点击开始使用 API,即可进入API 设置页面。
  5. 确保已关联一个 WhatsApp 商业账户(WABA)。如果您在步骤 3 中创建了新的业务组合,系统会自动生成一个账户,请在 API 设置页面中进行验证。

向导会按顺序要求您提供控制面板中的以下信息:

值控制面板位置字段类型备注
电话号码 ID应用控制面板 → WhatsApp → API 设置 → “发件人”下拉菜单下方数字,15–17位并非电话号码本身。最常见的错误就是将实际的电话号码粘贴至此处。
访问令牌应用控制面板 → WhatsApp → API 设置 → “生成访问令牌”以 EAA 开头,长度超过100个字符临时令牌有效期为24小时——如需用于正式环境,请参阅下方的“永久令牌”。
应用密钥应用控制面板 → 设置 → 基本设置 → 点击“显示”按钮32位小写十六进制字符串用于验证传入的webhook签名。若缺少此密钥,消息将因503错误而被拒绝接收。
应用 ID(可选)应用控制面板 → 设置 → 基本设置数字,15–16位发送消息时并非必需,但有助于数据分析。
WABA ID(可选)应用控制面板 → WhatsApp → API 设置 → 顶部附近数字,15位以上发送消息时并非必需,但有助于数据分析。

永久令牌(正式环境)

临时访问令牌的有效期为24小时,这意味着今天生成的令牌次日就会失效。对于正式环境部署,应使用系统用户永久令牌:

  1. 访问 business.facebook.com/latest/settings,在左侧导航栏中选择 System users。
  2. 点击 Add,输入名称(例如 hermes-bot),然后设置角色为 Admin。
  3. 选中新创建的用户,接着点击 Assign Assets:
    • 选择您的应用,在“Full control”选项下开启 Manage app。
    • 选择您的 WhatsApp 账户,在“Full control”选项下开启 Manage WhatsApp Business Accounts。
    • 点击 Assign assets。
  4. 使用以下权限生成令牌:
    • business_management
    • whatsapp_business_messaging
    • whatsapp_business_management
  5. 将令牌的过期时间设置为 Never。
  6. 复制生成的令牌,将其内容更新到 ~/.hermes/.env 文件中的 WHATSAPP_CLOUD_ACCESS_TOKEN 字段,最后重启网关。

除非您主动撤销,否则系统用户令牌不会过期。


将 Hermes 接入互联网

Cloud API 会通过 HTTPS POST 方式将接收到的消息发送到您的 webhook 地址——这意味着 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://<随机字符串>.trycloudflare.com 的网址):

cloudflared tunnel --url http://localhost:8090
请记下显示的URL——这就是您需要提供给Meta的地址。

::warning 快速隧道会定期更换 每次重新启动cloudflared后,免费的快速隧道URL都会发生变化。如需使用稳定的URL,请通过cloudflared tunnel login登录并创建一个命名隧道。免费Cloudflare账户可创建无限数量的命名隧道——有关命名隧道的操作流程,请参阅Cloudflare官方文档。

::

ngrok

ngrok http 8090

免费套餐在每次重启后都会显示不同的网址,而付费套餐则能为您提供稳定的子域名。

自有域名 + 反向代理

如果您已拥有配备 TLS 证书的服务器(如 Caddy、nginx 等),只需将路由指向 localhost:8090 即可。这是最适用于生产环境的稳定方案,但需要您预先准备好相关基础设施。


在 Meta 端配置 webhook

当您的隧道开始运行后:

  1. 记下隧道生成的公开网址——例如 https://abc123.trycloudflare.com。
  2. 生成一个验证令牌——向导会自动使用 secrets.token_urlsafe(32) 为您生成;如果您选择手动配置,则需执行相应命令:
    python -c "import secrets; print(secrets.token_urlsafe(32))"
    

在 ~/.hermes/.env 文件中,将该值保存为 WHATSAPP_CLOUD_VERIFY_TOKEN。 3. 启动 Hermes 网关:执行命令 hermes gateway。 4. 进入 Meta 应用控制面板 → WhatsApp → Configuration(具体路径可能因界面版本不同而显示为 Use cases → Customize → Configuration)→ 点击 Webhook 部分下的 Edit 按钮。 5. 填写以下内容:

  • Callback URL:https://abc123.trycloudflare.com/whatsapp/webhook
  • Verify Token:步骤 2 中获得的字符串(必须完全一致)
  1. 点击 Verify and save。Meta 会通过 GET 请求访问您的 URL,网关会回传验证挑战信息,随后 Meta 会将该 Webhook 标记为已验证。
  2. 在 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会限制机器人可以发送消息的号码范围:

  1. 进入“应用控制面板”→“WhatsApp”→“API设置”→收件人下拉菜单。
  2. 点击管理手机号码列表。
  3. 添加您希望向其发送消息的手机号码(包括您自己的、团队成员的以及合作测试人员的号码)。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×640像素。更改后会立即生效。
简介/描述/网站/邮箱/服务时间/类别“编辑个人资料”按钮用户点击机器人名称时,这些信息会显示在信息窗格中,仅用于美化展示。
已验证徽章(绿色对勾)Business Manager → 安全中心 → 开始验证需要经过 Meta 独立的商家验证流程。

hermes whatsapp-cloud 向导会在设置流程的最后提供这些链接。虽然这些内容并非机器人运行的必需项,但它们能提升机器人在用户眼中的呈现效果。


配置参考

所有设置均保存在 ~/.hermes/.env 文件中。必填值以粗体标出。

参数名默认值说明
WHATSAPP_CLOUD_PHONE_NUMBER_ID—来自 API 设置的 15–17 位数字标识符,并非电话号码。
WHATSAPP_CLOUD_ACCESS_TOKEN—Meta 访问令牌(以 EAA 开头),有效期为 24 小时,或为系统用户永久有效。
WHATSAPP_CLOUD_APP_SECRET—来自“设置”→“基本信息”选项的 32 位十六进制字符串,缺少该值会导致接收消息时返回 503 错误。
WHATSAPP_CLOUD_VERIFY_TOKEN—用于 GET 请求鉴权的共享密钥,由向导自动生成。
WHATSAPP_CLOUD_ALLOWED_USERS—以逗号分隔的 wa_ids 列表,指定允许向该机器人发送消息的用户。
WHATSAPP_CLOUD_ALLOW_ALL_USERSfalse设置为 true 可绕过用户白名单限制。
WHATSAPP_CLOUD_APP_ID—可选参数,用于未来集成分析功能。
WHATSAPP_CLOUD_WABA_ID—可选参数,用于未来集成分析功能。
WHATSAPP_CLOUD_WEBHOOK_HOST未设置(双栈模式:支持 IPv4 和 IPv6 的所有接口)Webhook 服务器绑定的接口地址。
WHATSAPP_CLOUD_WEBHOOK_PORT8090Webhook 服务器绑定的端口号,必须与隧道转发的端口一致。
WHATSAPP_CLOUD_WEBHOOK_PATH/whatsapp/webhookMeta 发送消息的 URL 路径。
WHATSAPP_CLOUD_API_VERSIONv20.0Meta Graph API 版本,仅当 Meta 的文档推荐使用更高版本时才需修改。
WHATSAPP_CLOUD_HOME_CHANNEL—用作机器人主通道的 wa_id(用于定时任务等场景)。
您可以将 Baileys(whatsapp)和 Cloud(whatsapp_cloud)两种适配器同时启用,针对不同的电话号码分别使用。

功能特性

接收消息

  • 文本消息——直接传递给智能体。
  • 图片——自动下载并附加到智能体的输入内容中。具备原生视觉功能的模型(如 Claude、GPT-4o、Gemini 等)可直接读取图片;不具备视觉功能的模型则会收到自动生成的文本描述。
  • 语音备忘录——自动下载为 .ogg 格式,通过您配置的文本转语音服务(如本地的 faster-whisper、OpenAI/Nous、Groq 等)进行转录,之后以文本形式传递给智能体。
  • 文档——自动下载。大小不超过 100KB、可读性良好的文本文件(如 .txt、.md、.json、.py、.csv 等)会直接嵌入到智能体的输入内容中,使其无需调用其他工具即可读取。较大文件则会缓存在本地,供智能体的其他工具使用。
  • 按钮点击——当用户点击机器人先前发送的按钮(如确认选项、批准指令、确认斜杠命令)时,该点击操作会直接路由到对应的处理函数。过期的点击操作则会被视为普通文本输入处理。
  • 回复上下文——当用户对机器人之前的消息进行回复时,智能体可以将原始消息作为上下文信息获取。

发送消息

  • 文本 — Markdown 格式会自动转换为 WhatsApp 特有的语法格式(**粗体** → *粗体*,~~删除线~~ → ~删除线~,标题则变为粗体,[链接](url) → 链接 (url))。过长的消息会按每 4096 个字符拆分传输。
  • 图片 — 支持由智能体生成的图片以及本地图片文件,均会以原生照片附件的形式发送。
  • 语音消息 — 文本转语音功能会通过 ffmpeg 转换为 WhatsApp 原生的语音消息格式(绿色波形图标)。若未安装 ffmpeg,则会退化为 MP3 音频附件。详情请参见下文的“语音消息”部分。
  • 视频/文档 — 两者均受支持,将以原生附件的形式发送。

交互式用户体验

当智能体触发上述任意流程时,Hermes 会使用 WhatsApp 原生的交互式消息功能——通过点击按钮来回应,而非要求用户输入“回复编号”:

  • clarify 工具 — 多项选择题会以快速回复按钮的形式呈现(1–3 个选项),或通过点击打开列表页(4 个及以上选项)。选择“✏️ 其他”后,用户可输入自由文本作为答案,智能体将此内容视为最终解答。
  • 危险命令审批 — 当智能体的终端/代码执行遇到受限命令时,用户会看到 ✅ 批准 / ❌ 拒绝 按钮,而无需手动输入 /approve 或 /deny。
  • 斜杠命令确认 — 对于如 /reload-mcp 这类具有特殊权限的命令,系统会显示 ✅ 仅批准一次 / 🔒 始终允许 / ❌ 取消 等按钮。

如果在某些情况下无法显示这些按钮(例如在旧版 WhatsApp 客户端上),所有交互式提示都会自动降级为纯文本形式。

已读回执与输入状态指示

Hermes 会立即确认收到的消息:

  • 一旦网关接收到您的消息,它就会显示蓝色双对勾。
  • 当智能体正在准备回复时,WhatsApp 聊天窗口中的机器人名称会显示为“正在输入…”。
  • 一旦智能体发出首条回复消息,该输入状态指示便会自动消失。

这样一来,就能清楚地分辨出机器人何时已看到您的消息,以及何时仍在处理回复。

语音消息

WhatsApp 会将“语音便签”(绿色波形气泡)与普通音频文件附件区分开来。两者的区别仅在于编码格式:语音便签必须为采用 opus 编码的 audio/ogg 格式。

而 Hermes 的文本转语音功能则生成 MP3 格式的音频。有两种处理方式:

  • 系统路径中已安装 ffmpeg(推荐)——输出的语音内容会被转换为标准的语音便签格式。安装方法如下:
    • Windows:winget install Gyan.FFmpeg
    • macOS:brew install ffmpeg
    • Linux:通过对应包管理器安装
  • 未安装 ffmpeg——输出的语音内容将以 MP3 音频附件的形式发送。虽然可以正常播放,但外观上并非语音便签格式。网关日志中会记录一次警告信息,以便您知晓。

您可以通过健康检查接口来查看网关是否找到了 ffmpeg:

curl http://localhost:8090/health
# look for "ffmpeg_present": true

已知限制

24小时对话窗口限制

Meta仅允许在用户最后一次发送消息后的24小时窗口内发送自由格式消息。超出该时间窗口后,Meta的API仅能接收经过预先审批的消息模板。

实际应用中的含义:

  • 反向聊天模式(用户发送私信 → 机器人在24小时内回复 → 用户再次回复……)可永久使用,这涵盖了95%以上的常规机器人使用场景。
  • 若通过定时任务在24小时间隔后向WhatsApp发送消息,将会因Graph错误代码131047(“重新互动消息”)而失败。
  • 耗时超过24小时的长时间运行的delegate_task异步操作也会出现同样的失败情况。
  • 那些将外部事件路由到WhatsApp的Webhook订阅者,在用户近期未向机器人发送私信时也会失效。

Hermes会在其系统提示中向代理发出关于此时间窗口的限制警告,因此模型在安排延迟发送的消息时会自动提及这一点。

目前Hermes尚未实现消息模板支持功能(即用于处理窗口外发送消息的替代方案)。如果您需要该功能,请提交问题——该功能已有规划,但仍在等待明确的用户需求信号。

群组聊天

Cloud API对群组聊天的支持较为有限(具体能力由Meta控制)。在v1版本中,Hermes的whatsapp_cloud适配器仅支持直接消息。如果您需要处理群组聊天,请使用Baileys桥接方案。

发送消息速率限制

Meta的默认吞吐量为每个企业电话号码每秒80条消息,也可选择升级更高额度。Hermes目前并未在客户端侧强制执行此限制——但超高频率的发送操作仍可能触及Meta的限制。


故障排除

在Meta控制台中出现设置验证失败(“无法验证URL”)的情况

通常由以下原因之一导致:

  • 隧道URL错误或已过期——cloudflared的快速隧道会定期更换。请获取新的URL,并同步更新.env文件及Meta控制台中的配置。
  • 验证令牌不匹配——~/.hermes/.env文件中WHATSAPP_CLOUD_VERIFY_TOKEN字段的值必须与在Meta控制台输入的值完全一致。建议先运行上述curl测试,确认本地网关的验证流程能够正常工作。
  • 网关未运行——请检查hermes gateway服务是否处于启动状态。
  • 未设置应用密钥——若缺少该密钥,Hermes会以503错误拒绝接收POST请求,而Meta则会将其解读为“无法验证”。

graph error 100:编号为‘…’的对象不存在

您可能将电话号码(10-11位)直接填入了WHATSAPP_CLOUD_PHONE_NUMBER_ID字段,而非Meta系统使用的电话号码ID(15-17位内部编号)。请重新查看API设置页面——电话号码ID显示在“发件人”下拉菜单的下方。

虽然现在向导已通过验证工具检测此类错误,但如果您是手动配置的话,了解这一点仍很有帮助。

graph error 190:认证错误

您的访问令牌无效。相关子代码包括:

  • subcode 463 — 令牌已过期。临时令牌的有效期为24小时。请重新生成令牌,或切换为系统用户的永久令牌(参见上文)。
  • subcode 467 — 令牌失效(已被撤销或密码已更改)。
  • 其他值190 — 生成的令牌不具备所需的权限。请确保已选中全部三项权限:business_management、whatsapp_business_messaging和whatsapp_business_management。

graph error 131047:重新建立对话提示

24小时的对话窗口已到期(参见“已知限制”)。您可以:

  • 要求用户先通过私信与机器人沟通,以重新开启对话窗口;
  • 等待Hermes支持模板功能。

接收到的消息:media metadata fetch failed (status=401)

其根本原因与发送消息时出现的401错误相同(graph error 190)——访问令牌无效或已过期。请修复该令牌。

机器人的回复显示为原始JSON格式/工具调用信息泄露

常见原因在于为whatsapp_cloud配置的工具集缺少机器人所需调用的工具。请查看hermes tools list,并确认平台使用的是hermes-whatsapp(即默认的云适配器工具集,与Baileys相同)。

如果模型输出的内容呈现为类似工具调用的文本,而非结构化的调用指令,通常意味着工具集实际上为空。有关平台与默认工具集的对应关系,请参阅hermes_cli/platforms.py文件。

STT(语音笔记转录)功能返回空值/“无法转录”

默认的 stt.provider: local 设置需要先执行 pip install faster-whisper。如果您是 Nous 的订阅用户,可以通过托管网关来实现文本转语音功能——在 hermes tools 中选择 Nous Subscription 选项,或直接进行相应设置即可。

hermes config set stt.provider nous
hermes gateway restart

该方案使用您的 Nous Portal 访问令牌,无需单独的 OpenAI 密钥。(旧版文档建议设置 stt.use_gateway true——该标志已过时;如今路由逻辑仅由提供商选择来决定。)


安全注意事项

  • 将应用密钥视同密码对待——任何获取到该密钥的人都可以伪造 webhook 请求体,而 Hermes 会将其视为合法数据予以接收。
  • 验证令牌属于共享密钥——虽然其泄露带来的风险相对较低(最坏情况下只是有人将自己的 Meta webhook 重新指向其他网址),但仍应避免将其泄露。
  • 访问令牌代表您机器人的身份——系统用户令牌相当于长期有效的 API 密钥。若部署环境遭到入侵,应立即更换令牌。
  • 当设置了 WHATSAPP_CLOUD_APP_SECRET 时,webhook 端点仅接受已签名请求——即使在开发环境中也应保持该设置。若未设置,网关会以 HTTP 503 错误拒绝接收请求。
  • /health 端点无需身份验证——由于它仅返回配置是否存在的相关布尔值,而非具体配置内容,因此公开该端点是安全的。但如果您不愿公开它,也可在反向代理或隧道层进行访问限制。

与 Baileys bridge 的对比

Baileys(hermes whatsapp)云 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格式
已读回执不支持支持(显示蓝色双对勾)
输入中状态指示不支持支持(收到回复后会自动消失)
交互式按钮仅支持文本选项原生支持(包括“确认”、“批准”、“slash-confirm”等功能)
生产环境使用存在风险(可能被 Meta 封禁)专为生产环境设计

大多数将 Hermes 用于个人项目的用户更倾向于选择 Baileys,而那些开发面向客户的机器人的用户则更常选择云 API。


参见