Webhooks
Webhooks 让 Your AI Connector 能够在发生重要事件(例如创建新联系人、预约成功或收到消息)时,自动通知您的其他业务工具。您的连接系统无需手动检查更新,即可在事件发生时立即收到通知。
什么是 Webhooks?
可以将 Webhook 想象成两个应用程序之间的自动短信。当 Your AI Connector 中发生某些事情(例如有新联系人注册)时,平台会立即向您选择的另一个系统发送通知。您需要提供一个 Web 地址(称为“Webhook URL”)来接收这些通知,该地址通常由您的 CRM、自动化平台或开发人员提供。
Webhook 仅将数据发送出 Your AI Connector。 Webhook 是从 Your AI Connector 到您的其他工具的单向通道。不存在可以将潜在客户、联系人或消息发送到平台内部的 Webhook URL。 要推入新的潜在客户(例如来自网站表单、您的 CRM 或 GoHighLevel),您的系统需要改为进行 API 调用。请参阅 API 访问(“创建联系人”操作)和 漏斗。对于入站方向,您唯一需要的是您的 API 密钥,它位于其专属部分中 — 请参阅 API 访问。此处描述的 Webhook 页面仅用于出站方向。
注意: 设置 Webhooks 涉及一些技术配置。如果您对此不熟悉,请将此页面分享给您的开发人员,或者使用 Zapier、Make 或 Pabbly 等自动化平台,它们提供的 Webhook URL 无需编写代码即可使用。
常见用途包括:
- 将新联系人同步到您的 CRM。
- 当应用标签时,触发 Zapier、Make 或 Pabbly 中的工作流。
- 当有人发出警报时,在 Slack 中通知您的团队。
- 当预约成功时,更新您的日历系统。
- 将对话摘要记录到您的数据库中。
设置 Webhooks
- 在左侧边栏中,点击 Settings(齿轮图标)。
- 在 Settings 侧边栏的 Integrations 组下,点击 Webhooks。
在尚未配置任何 Webhook 的账户中,页面显示如下:
- 点击右上角的 New webhook。页面上会打开一个内嵌表单:
- 填写:
- 端点 URL — Your AI Connector 将向其发送事件通知的 Web 地址。您可以从外部系统(CRM、自动化平台或自定义服务器)获取此地址。
- 名称 — 您稍后可以识别的标签(例如“Slack 提醒”或“CRM 同步”)。仅供您参考。
您的 webhook URL 必须是公开可访问的
https://地址。 普通的http://地址、localhost或私有网络地址以及平台内部地址在保存时会被拒绝。若要从您自己的机器进行测试,请使用公共隧道(如 webhook.site 或 ngrok)代替 localhost。
- 在事件 (Events) 下,勾选您希望此 Webhook 接收的事件 — 所有 22 个事件均列在 22 个 Webhook 事件 中。
- (可选) 如果您希望 Your AI Connector 在临时故障时持续重试,请开启 重试失败的投递 (Retry failed deliveries) — 请参阅 重试失败的投递。
- 点击 创建 Webhook (Create webhook)。它会出现在表单下方的列表中,您可以随时点击其所在行的 测试 (Test),向您的端点发送一个示例负载。
需要权限。 添加、编辑或测试 webhook 需要“集成”的“编辑”权限(仅查看权限的团队成员将看到只读通知,而不是表单)。
签名 webhook 需要先保存它 — 打开现有 webhook 的行进行编辑,Signing secret 面板会出现在编辑表单的底部。全新的、未保存的草稿尚无签名选项 — 请参阅下方的 签名负载。
为所有客户账户使用一个 Webhook(代理机构)
如果您经营一家代理机构,则无需在每个客户账户上重复创建相同的 Webhook。在代理账户中,Webhook 表单会多出一个开关:Also fire for all client accounts(同时触发所有客户账户)。开启此项后,该 Webhook 也会接收到您代理机构下每个客户账户发生的事件 — 一个端点,覆盖整个代理机构。
其工作方式如下:
user代码块会告知您事件所属的客户。 每条通知都已包含一个user代码块,用于标识事件发生的账户,因此您的自动化程序可以按客户进行路由。- 您的 Webhook 设置适用于所有地方。 您选择的事件、签名密钥和重试设置也会用于客户账户的交付。
- 不会重复交付。 如果某个客户账户有自己的 Webhook 指向同一个 URL,则该 Webhook 将用于处理该账户的事件 — 同一个事件永远不会两次到达同一个端点。
- 客户无法看到它。 该 Webhook 不会出现在客户账户自己的 Webhooks 页面上,客户也无法将其关闭 — 它完全由您管理。
- 可靠性按客户账户进行跟踪。 如果您的端点持续失败,它将自动为交付失败的账户关闭(请参阅 Webhook 可靠性),而不是一次性关闭整个代理机构的 Webhook。
该开关仅在代理账户中显示。同时也支持通过 API 进行设置 — 请参阅 Webhooks API 中的 apply_to_sub_accounts 字段。
可用触发事件
您可以独立启用或禁用这 22 个 Webhook 事件中的每一个。当事件触发时,Your AI Connector 会将包含相关数据的通知发送到您的 Webhook URL。每个事件及其含义,以及它在负载中放入的 event 代码,都一起列在本页下方的 22 个 Webhook 事件 中。
温馨提示: 任务已创建、任务已更新和任务已完成是完全可选的,并且可以正确保存。每日摘要已创建也是最近新增的。有关该负载格式的信息,请参阅下方的任务已完成 Webhook。
基于标签的 Webhook 触发器
subscribed_to_tags 不会将 Webhook 的事件限定在某个标签内。它仅用于缩小哪些标签会产生对话摘要通知。若要在应用特定标签时获取请求,请在代理(或营销活动)的标签选项卡中为该标签设置 Webhook URL。
Webhook 表单本身没有标签选择器,无论是创建新 Webhook 还是编辑现有 Webhook 时都没有,因此 subscribed_to_tags 只能通过Webhooks API读取或更改,或者通过联系支持团队进行处理。
值得注意: 编辑现有的包含
subscribed_to_tags列表的 Webhook(重命名、更改事件、切换重试设置)不再会清除该列表——由于表单中没有用于回传的标签选择器,现在从该页面保存将保持现有列表不变。(在 2026年7月21日 之前,这是一个真正的 Bug:从 Webhook 表单保存时总是会发送一个空的标签列表,从而导致列表被擦除。如果 Webhook 在该日期之前丢失了其subscribed_to_tags列表,则需要通过 API 重新配置。)
为已标记的联系人生成摘要
如果 Webhook 具有 subscribed_to_tags 列表,您可以开启生成摘要。启用后,当应用其中一个标签时,Your AI Connector 会自动为联系人生成对话摘要,并将其包含在 Webhook 数据中 — 无需单独请求即可获取完整上下文。
测试您的 Webhook
- 打开 设置 → 集成 → Webhooks。
- 在您的 webhook 行中,点击 测试。
- 检查您的外部系统,确认其已收到测试数据。
- 查看数据格式,确保您的系统能够正确解析它。
为了进行完整的端到端测试,请发送一条会触发您所配置事件的消息(广播,或已连接频道上的传入消息),并验证 webhook 是否使用真实数据触发。
提示: 在开发过程中,使用 webhook.site 或 RequestBin 等工具来检查原始 webhook 数据,然后再连接您的生产系统。
什么算作成功投递
无论您是点击 测试 还是事件真实触发,我们发送的内容都是一样的:
- 一个 POST 请求(绝非 GET),主体为 JSON 格式,且包含
Content-Type: application/json。 - 签名负载下列出的标头。仅在您设置了签名密钥后,才会包含签名标头。
当满足以下条件时,我们将投递视为成功:
- 您的端点以 任何 2xx 状态码(200、201、204 等均可)响应。
- 它在 30 秒内 做出响应。
一些容易让人感到意外的情况:
- 响应体会被忽略。 您无需返回任何特定的 JSON。返回一个空的 200 状态码即可。
- 重定向会被视为失败。 我们不会跟随重定向,因此 301 或 302(包括末尾斜杠重定向,或从 http 到 https 的重定向)会被记录为投递失败。请保存最终的 URL,而不是会重定向的 URL。
- 完全支持查询字符串。
https://your-app.com/hook?token=abc123会按照您保存的原样发送,因此将令牌放在查询字符串中与放在路径中效果一样。 - 您的 URL 必须是
https://且可公开访问。 属于 Your AI Connector 自身基础设施的地址会被拒绝,但您在 Google Cloud Functions、Cloud Run、App Engine、Firebase Hosting 或其他任何地方的端点均可正常使用。 - 端点前的防火墙或机器人防护层可能会拦截我们。 最常见的情况是 Cloudflare:如果您的区域开启了“机器人对抗模式 (Bot Fight Mode)”或托管挑战,我们的请求会收到一个带有 403 状态码的“请稍候…”挑战页面,而不是到达您的服务器——而服务器到服务器的请求永远无法通过浏览器挑战,因此“测试”按钮和实际事件都会以同样的方式失败。“测试”按钮会在发生这种情况时通知您(“Cloudflare 正在向我们的请求显示机器人挑战”)。请在 Cloudflare 中通过安全/WAF 规则修复此问题,跳过对您的 Webhook 路径(或针对
Webhook-Delivery/1.0用户代理)的挑战,然后再次点击“测试”。 - 如果您的防火墙需要 IP 白名单(例如 Cloudflare 的免费计划,普通的“机器人对抗模式”无法通过 WAF 规则跳过,但设置为“允许”的 IP 访问规则可以在其之前运行),我们可以提供帮助:每次投递,无论是来自“测试”按钮还是实时事件,都是从一个固定的 IPv4 地址发送的(没有范围,没有 IPv6,不会轮换)。请联系支持团队,我们将为您提供需要加入白名单的地址。请保留签名验证作为您实际的信任检查,因为它会验证每个有效载荷,无论其来自何处。
- 测试结果会准确告诉您端点的响应内容。 测试失败现在会显示真实原因(您的端点返回的 HTTP 状态码、超时,或者我们完全无法连接到该地址),而不是通用的错误信息;并且在开启签名功能时,已保存 Webhook 的测试也会像实时事件一样进行签名发送。
使用 n8n、Make 或 Zapier(“测试 URL”与“生产 URL”)
自动化平台通常会为您提供两个不同的 webhook 地址,这往往会让人困惑:
- 测试 URL(在 n8n 中包含
/webhook-test/)。它仅在您主动观察画布并刚刚点击了 监听测试事件(或 测试工作流)时才会接收数据。它捕获单个事件后就会停止监听——因此在 Your AI Connector 中连续多次点击 测试 只会捕获到第一个,且仅当监听窗口在该特定时刻处于活动状态时才有效。测试方法:先在 n8n 中点击 监听测试事件,然后回到 Your AI Connector 点击一次 测试。 - 生产 URL(在 n8n 中包含
/webhook/,不含-test)。这是用于实时事件并粘贴到 Your AI Connector 中的 URL。它仅在您的工作流切换为 激活 (Active) 后才有效。如果工作流未激活,n8n 会以“404 / webhook 未注册”错误拒绝请求,即使 Your AI Connector 已正确发送了数据。
简而言之:在监听时使用测试 URL 进行测试,但为了让 webhook 能持续处理真实联系人,请在 Your AI Connector 中保存 生产 URL 并确保工作流处于 激活 (Active) 状态。
Webhook 数据格式
当 Webhook 触发时,Your AI Connector 会将结构化数据 (JSON) 发送到您的 Webhook URL。如果您使用的是 Zapier 或 Make 等自动化平台,它会自动为您解析这些数据。如果您正在构建自定义集成:
{
"event": "contactCreated",
"contact": { "id": "<contact-id>", "first_name": "Jane", "...": "..." },
"campaign": { "id": "<campaign-id>", "name": "AI Receptionist", "status": "Live" },
"agent": { "id": "<agent-id>", "name": "Front Desk" },
"user": { "id": "<account-id>", "email": "owner@example.com" }
}
| 字段 | 描述 |
|---|---|
event |
触发通知的确切事件字符串(例如 contactCreated, booked)。这不是事件列表中显示的显示标签;每个标签及其对应的代码都在 22 个 Webhook 事件 中。 |
contact |
该事件相关的联系人,或者对于不与联系人绑定的事件(如 creditsRecharged),则为 null。 |
campaign |
联系人所属的营销活动,如果没有,则为 null。 |
agent |
处理对话的坐席,如果没有,则为 null。 |
user |
拥有该数据的账户的基本身份信息。 |
campaign或agent— 通常二者居其一,不会同时存在。 如果您的账户使用坐席,您的联系人将归属于坐席而非营销活动,因此campaign将显示为null,而agent会告知您具体由哪位坐席处理。较旧的基于营销活动的账户则相反。请读取已填充的字段;不要假设campaign总是存在。
agent模块于 2026 年 8 月 15 日上线。 它与campaign一起出现在与对话相关的事件中——包括已结束的聊天、请勿打扰、恢复、取消归档、AI 暂停、新消息、对话摘要以及您可以为标签设置的 webhook——并携带处理代理的id和name,或者在没有代理参与时携带null。它是纯粹的增量更新:您已经接收到的每个字段都保持不变,因此您在该日期之前构建的接收器无需任何更新即可继续工作。
有些事件会添加其自己的额外顶级块。例如,Appointment Booked(预约已预订)会添加一个 appointment 块(请参阅 Appointment Booked Webhook),New Message(新消息)会添加一个包含文本的完整 message 块(请参阅 New Message Webhook),而 Deliveries(送达)和 Reads(已读)会添加一个仅包含消息 ID 和状态的简短 message 块(请参阅 Deliveries and Reads Webhook)。
送达和已读回执会告知您是哪条消息,但不会显示具体内容。 它们携带一个
message代码块,其中包含消息的id和status—— 该id与 发送消息端点 返回的messageId相同,因此您可以将送达或已读回执与您发送的确切消息进行匹配 —— 但不包含消息正文。回复则完全不携带message代码块。如果您需要获取发送或接收的具体文字内容,请同时订阅新消息事件。
在编写接收器之前需要了解两件事。 没有
timestamp字段,也没有data包装器。每个块都位于 JSON 对象的顶层,如上所示。
22 个 Webhook 事件
这 22 个 Webhook 事件,包含您在应用中勾选的显示标签以及负载中发送的 event 代码。event 代码是一个短字符串,它不匹配显示标签,因此请根据代码而非标签来匹配您的接收器:
| 显示标签(在应用中) | 有效负载中的 event 代码 |
含义 |
|---|---|---|
| Contact Created(联系人已创建) | contactCreated |
您的账户中添加了新联系人(手动、通过导入或通过 API)。 |
| Contact Paused(联系人已暂停) | contact_paused |
联系人对话已暂停(机器人停止响应)。 |
| Contact Resumed(联系人已恢复) | contact_resumed |
已暂停的联系人对话已恢复。 |
| Contact Do Not Disturb(联系人请勿打扰) | contact_do_not_disturb_changed |
开启了联系人的“请勿打扰”设置。 |
| Contact Unarchived(联系人已取消归档) | contact_unarchived |
已归档的联系人发送了新消息,将其带回您的活动收件箱。 |
| New Message(新消息) | new_message |
任何渠道的对话中添加了任何消息 —— 包括联系人发送给您的消息,以及您的 AI 或团队发送给他们的消息。这是唯一携带实际消息文本的事件(请参阅 New Message Webhook)。 |
| Replies(回复) | replied |
联系人回复了消息。 |
| Reads(已读) | read |
联系人已阅读消息(在支持已读回执的渠道上)。携带已读消息的 ID —— 请参阅 Deliveries and Reads Webhook。 |
| Deliveries(送达) | delivered 或 undelivered |
消息已成功送达联系人(undelivered 表示送达失败)。携带消息的 ID —— 请参阅 Deliveries and Reads Webhook。 |
| Human Alerted(已提醒人工) | humanAlerted |
AI 机器人确定无法处理对话,并将其标记为需要人工处理。 |
| Chat Concluded(聊天已结束) | chat_concluded |
AI 机器人判定对话已结束(已完成预约、潜在客户被取消资格等)。 |
| Appointment Booked(预约已预订) | booked |
联系人通过预约系统预订了预约。 |
| Credits Spent(积分已消耗) | creditsSpent |
积分已从您的账户中扣除。 |
| Credits Recharged(积分已充值) | creditsRecharged |
积分通过自动充值或手动购买添加到您的账户中。 |
| Low Credit Balance(积分余额不足) | lowCreditBalance(测试发送时),Low Credit Balance(实际发送时) |
提前警告您的积分余额已降至警报阈值以下(除非您自行设置,否则为 100 积分)。针对代理机构,其所有子账户均从一个池中扣除积分。它携带 balance、threshold 和 account_email 而不是联系人块,在余额保持较低水平时最多每 24 小时发送一次,并在余额回升至阈值以上时立即重新启用。 |
| Task Created(任务已创建) | taskCreated |
任务已创建。 |
| Task Updated(任务已更新) | taskUpdated |
任务发生变更,但未进入完成阶段。 |
| Task Completed(任务已完成) | taskCompleted |
任务进入了配置为完成阶段的阶段。 |
| Daily Summary Created(每日摘要已创建) | dailySummaryCreated |
您的每日摘要报告已生成。 |
| Channel Connected(渠道已连接) | channelConnected |
尚未发送 —— 可选择,但目前没有任何内容会触发它。请勿基于此构建。 旨在用于消息传递渠道完成连接时。 |
| Broadcast Started(广播已开始) | broadcastStarted |
广播开始发送(其状态变为 Sending)。每次开始时触发,包括恢复已暂停的广播时。携带一个 broadcast 块而不是联系人块:id、name、channel、status、previous status、目标列表(list_id、list_name、is_smart_list)、scheduled_at、total_contacts。 |
| Broadcast Completed(广播已完成) | broadcastCompleted |
广播完成(其状态变为 Sent 或 Failed)。相同的 broadcast 块加上 completed_at,以及在可用时包含 completion_summary(total_sent、permanently_failed、unique_replied、failure_rate、had_errors)。使用这两个事件将智能广播列表连接到外部工具。 |
还有两个代码永远不会出现在该列表中,因为您不会订阅它们:contact_tags_updated(由设置在单个标签上的 Webhook URL 发送)和 summary_generated(当为 Webhook 的 subscribed_to_tags 列表中的标签编写聊天摘要时发送)。
“频道已连接”尚未发送。 它出现在事件列表中,但目前没有任何内容会触发它。请勿基于此进行开发。
基于标签和任务的通知使用其各自独立的结构。请参阅 联系人标签已更新 和 任务已完成。
联系人已创建 Webhook
当 联系人已创建 (Contact Created) 事件触发时发送(通过手动、导入或 API 添加新联系人)。
事件名称
contactCreated
有效载荷格式
{
"event": "contactCreated",
"contact": {
"id": "<contact-id>",
"email": "jane@example.com",
"phone_number": "+15551234567",
"first_name": "Jane",
"last_name": "Smith",
"human_alerted": false,
"human_alert_reason": null,
"is_bot_active": true,
"ad_referral": null
},
"campaign": {
"id": "<campaign-id>",
"name": "AI Receptionist",
"status": "Live"
},
"agent": {
"id": "<agent-id>",
"name": "Front Desk"
},
"user": {
"id": "<account-id>",
"email": "owner@example.com",
"first_name": "Alex",
"last_name": "Doe"
}
}
| 字段 | 描述 |
|---|---|
event |
此事件始终为 contactCreated。 |
contact.id |
新联系人的唯一 ID。 |
contact.email / contact.phone_number |
联系人的电子邮件和电话(如果已知,具体取决于渠道,可能为空)。 |
contact.first_name / contact.last_name |
联系人的姓名(如果已知)。 |
contact.human_alerted / contact.human_alert_reason |
联系人是否被标记为需要人工关注,以及原因。 |
contact.is_bot_active |
AI 机器人当前是否在该联系人上处于活动状态。 |
contact.ad_referral |
Meta 点击通话 WhatsApp (Click-to-WhatsApp) 广告归因,或 null — 请参阅 点击通话 WhatsApp 广告归因。 |
campaign |
创建该联系人时所属的营销活动,或 null。 |
agent |
分配给该联系人的坐席,或 null。 |
user |
拥有该联系人的账户的基本身份信息。 |
“测试”样本与真实事件看起来略有不同。 测试按钮会发送占位符数据(John Doe,一个示例营销活动)。真实的“联系人已创建”事件包含联系人的实际详细信息,根据渠道的不同,某些字段可能为空。
新消息 Webhook
此 Webhook 在每次向对话添加消息时触发,适用于任何渠道。它涵盖了两个方向:联系人发送给您的消息,以及您的 AI、团队或营销活动发送给他们的消息。这是唯一包含消息文本的 Webhook,因此当您希望将对话镜像到外部系统时,请使用此 Webhook。
事件名称
new_message
有效载荷格式
{
"event": "new_message",
"contact": {
"id": "<contact-id>",
"email": "jane@example.com",
"phone_number": "+15551234567",
"first_name": "Jane",
"last_name": "Smith",
"human_alerted": false,
"human_alert_reason": null,
"is_bot_active": true,
"ad_referral": null
},
"agent": {
"id": "<agent-id>",
"name": "Front Desk"
},
"user": {
"id": "<account-id>",
"email": "owner@example.com",
"first_name": "Alex",
"last_name": "Doe"
},
"message": {
"id": "<message-id>",
"body": "Hi, are you open on Saturday?",
"direction": "inbound",
"status": "received",
"created_at": "2026-07-30T17:27:06.000Z",
"channel": "whatsapp_web"
}
}
| 字段 | 描述 |
|---|---|
event |
此事件始终为 new_message。请注意,这是发送的确切字符串 —— 它不是显示标签“New Message”。 |
contact |
消息所属对话的联系人。形状与 Contact Created 中的相同。 |
agent |
处理对话的座席(id 和 name),如果没有座席参与,则为 null。 |
user |
拥有该对话的账户的基本身份信息。 |
message.id |
消息的唯一 ID。 |
message.body |
消息文本。对于仅携带附件(图像、语音备忘录、文档)的消息,此项为空。 |
message.direction |
inbound 表示来自联系人的消息,outbound 表示由您的 AI 或您的团队从收件箱发送的消息,outbound-api 表示由营销活动、广播、模板发送或 API 发送的消息。 |
message.status |
消息在其生命周期中所处的位置:received 表示传入,queued / sent / delivered / read / failed / undelivered 表示传出。这是消息创建时刻的状态,因此传出消息通常在此处显示为 queued 或 sent,随后达到 delivered —— 如果您需要这些后续转换,请使用 Deliveries(送达)和 Reads(已读)事件。它们携带与此块相同的 message.id,因此您可以将转换与此消息匹配(请参阅 Deliveries and Reads Webhook)。 |
message.created_at |
消息创建时间,以 UTC 为单位(ISO 8601)。 |
message.channel |
消息通过的渠道,例如 whatsapp、whatsapp_web、sms、instagram、messenger、telegram、email 或 custom。 |
此负载中仍然没有
campaign模块。 新消息发送contact、agent、user和message。agent模块于 2026 年 8 月 15 日 添加,用于告知您处理该对话的代理;如果您还需要营销活动上下文,请使用contact.id通过 API 查询联系人。
内部 AI 记录不会触发此 Webhook。 除了真实消息外,平台还在对话中保留其自己的簿记行(AI 的工具调用和内部轮次记录)。这些永远不会被发送——您只会收到真正发送或接收的消息。
Deliveries and Reads Webhook
这两个事件报告了消息在离开 Your AI Connector 之后发生的情况:Deliveries(送达)在消息到达联系人(或送达失败)时触发,Reads(已读)在支持已读回执的渠道上,当联系人打开消息时触发。
两者都携带一个 message 块,其中包含该事件相关消息的 ID,因此您可以将更新与您发送的确切消息进行匹配。
事件名称
delivered 和 undelivered 用于 Deliveries(送达),read 用于 Reads(已读)。
有效载荷格式
{
"event": "delivered",
"contact": {
"id": "<contact-id>",
"email": "jane@example.com",
"phone_number": "+15551234567",
"first_name": "Jane",
"last_name": "Smith",
"ad_referral": null
},
"campaign": {
"id": "<campaign-id>",
"name": "AI Receptionist",
"status": "Live"
},
"agent": {
"id": "<agent-id>",
"name": "Front Desk"
},
"user": {
"id": "<account-id>",
"email": "owner@example.com",
"first_name": "Alex",
"last_name": "Doe"
},
"message": {
"id": "<message-id>",
"status": "delivered"
}
}
| 字段 | 描述 |
|---|---|
event |
delivered 或 undelivered 用于 Deliveries(送达),read 用于 Reads(已读)。 |
contact |
消息发送到的联系人。 |
campaign |
联系人所属的营销活动,或 null。 |
agent |
处理对话的座席,或 null。 |
user |
拥有该数据的账户的基本身份信息。 |
message.id |
此更新相关消息的 ID。它与 发送消息端点 返回的 messageId 值相同,也与 New Message 通知携带的 message.id 相同。 |
message.status |
新状态,始终与 event(delivered、undelivered 或 read)的字符串相同。 |
如何将更新与您发送的消息匹配。 存储您通过 API 发送消息时返回的
messageId。当 Deliveries(送达)或 Reads(已读)通知到达时,根据有效负载中的message.id查找该存储的 ID —— 这就是该确切消息的送达或已读回执。
此处没有消息文本。
message块仅携带 ID 和状态。如果您还需要正文,请订阅 New Message。
仅当我们知道它是哪条消息时,才会出现
message块。 在极少数无法关联到已存储消息的更新中,该块会被完全省略,而不是发送为空 —— 因此在读取message.id之前,请检查message是否存在。
每个状态更改对应一个通知。 单条传出消息通常会产生一个
delivered通知,然后在支持已读回执的渠道上,产生一个read通知。发送失败会产生undelivered。
预约已预订 Webhook
当联系人预订预约时触发。无论是由 AI 在对话中预订、您手动预订,还是通过 API 预订,它的触发方式都是相同的。
事件名称
booked
有效载荷格式
{
"event": "booked",
"contact": {
"id": "<contact-id>",
"email": "jane@example.com",
"phone_number": "+15551234567",
"first_name": "Jane",
"last_name": "Smith"
},
"campaign": {
"id": "<campaign-id>",
"name": "AI Receptionist",
"status": "Live"
},
"user": {
"id": "<account-id>",
"email": "owner@example.com"
},
"appointment": {
"appointment_id": "<appointment-id>",
"start_time": "2026-07-20T15:00:00.000Z",
"end_time": "2026-07-20T15:30:00.000Z",
"status": "confirmed",
"room_name": "Room 1",
"description": "Discovery call",
"summary": "30 min intro",
"google_calendar_event_id": null,
"event": {
"id": "<service-id>",
"event_name": "Intro Call",
"slot_duration": 30,
"location": "Zoom",
"meeting_link": "https://...",
"event_type": "online"
}
}
}
| 字段 | 描述 |
|---|---|
event |
对于此事件始终为 booked。 |
contact |
预订人。根据渠道的不同,email 和 phone_number 可能为空。 |
appointment.appointment_id |
预订的唯一 ID。 |
appointment.start_time / end_time |
预订时段的开始和结束时间(UTC,ISO 8601 格式)。 |
appointment.status |
预订的当前状态。 |
appointment.room_name |
预订所在的房间(如果使用)。 |
appointment.description / summary |
预订时捕获的自由文本详情。 |
appointment.google_calendar_event_id |
Google 日历的同步事件 ID。在“预约已预订”Webhook 中,它通常为 null,因为日历事件是在发送通知的同一时刻创建的 — 如果需要,请稍后通过其 appointment_id 重新获取预约;对于未连接 Google 日历的账户,请预期得到永久的 null。 |
appointment.event |
已预订的服务:名称、时段长度、地点、会议链接、类型。 |
google_calendar_event_id在此 Webhook 中通常为null,这是正常的。 Google 日历活动是在此通知发出的同时创建的,因此 ID 通常尚未准备好。如果需要,请稍后通过其appointment_id重新获取预约。如果账户未连接 Google 日历,它将永久保持null,因此请勿无限期等待。
“测试”按钮不包含
appointment块。 请使用它来确认您的端点是否响应,然后进行一次真实预约以查看完整负载。
此 Webhook 不会触发的两种情况: 从外部日历导入的预约,以及通过 Formitable 集成进来的预订。
联系人标签更新 Webhook
当标签被应用于联系人,且该标签在联系人所属的坐席或营销活动中配置了 Webhook URL 时触发。
事件名称
contact_tags_updated
触发时机
- 标签被应用于已分配坐席、已分配营销活动或两者兼有的联系人。
- 至少有一个已应用的标签在相应坐席或营销活动的“标签”选项卡中设置了 Webhook URL。
如果联系人两者皆有,且营销活动的标签带有 webhook URL,则以营销活动的为准;否则使用代理的设置。
如果在同一次更新中应用了多个具有不同 Webhook URL 的标签,则每个 URL 会发送一个请求,且每个请求仅包含映射到该 URL 的标签。
移除标签绝不会发送请求。 大多数人将这些 URL 指向某个操作(例如收取押金、预订时段、提醒代表),因此如果移除标签会导致重新运行该操作,那是不可能的。当移除操作与指向同一 URL 的应用操作在同一次更新中发生时,移除操作仍会显示在 removed_tags 中,因此读取这两个数组的自动化程序可以保持完整视图;但它永远不会看到仅由移除操作引起的请求。(于 2026 年 8 月 12 日更改。在此日期之前,移除操作也会发送请求。)
有效载荷格式
{
"event": "contact_tags_updated",
"contact": {
"id": "<contact-id>",
"email": "jane@example.com",
"phone_number": "+15551234567",
"first_name": "Jane",
"last_name": "Smith",
"human_alerted": false,
"is_bot_active": true,
"ad_referral": {
"ctwa_clid": "ARAbc123...",
"source_id": "120210000000000",
"source_type": "ad",
"source_url": "https://fb.me/xxxx",
"headline": "Get 20% off today",
"body": "Message us now to claim your discount",
"channel": "whatsapp"
}
},
"added_tags": ["qualified-lead"],
"removed_tags": ["new-lead"],
"agent": {
"id": "<agent-id>",
"name": "Front Desk"
},
"user": {
"email": "owner@example.com",
"first_name": "Alex",
"last_name": "Doe"
}
}
| 字段 | 描述 |
|---|---|
event |
此 webhook 始终为 contact_tags_updated。 |
contact.id |
标签发生更改的联系人的唯一 ID。 |
contact.email / contact.phone_number |
联系人的电子邮件/电话(如果已知)。 |
contact.first_name / contact.last_name |
联系人姓名。 |
contact.human_alerted |
联系人当前是否被标记为需要人工关注。 |
contact.is_bot_active |
AI 机器人当前是否在此联系人的对话中处于活动状态。 |
contact.ad_referral |
仅当联系人首次通过 Meta 点击跳转 WhatsApp (CTWA) 广告或帖子联系您时出现。否则为 null。 |
added_tags |
此更新中应用的标签名称数组。绝不为空——应用操作是触发请求的原因。 |
removed_tags |
同一更新中移除的标签名称数组(如有)。仅移除标签不会发送任何内容。 |
agent |
处理该联系人对话的代理(id 和 name),如果无代理参与则为 null。于 2026 年 8 月 15 日 添加。 |
user |
拥有该联系人的账户的基本身份信息。 |
测试标签 Webhook
在“标签”选项卡中,Webhook URL 字段旁边有一个 测试 按钮。它会立即向该 URL 发送一个示例负载,以便您在等待真实对话之前确认您的自动化系统能够接收到它。
该测试发送的 contact_tags_updated 形状与上方显示的一致,使用一个占位符联系人,其中您正在测试的标签位于 added_tags 中,且 removed_tags 为空。您的自动化系统在测试中看到的内容即为它在生产环境中将看到的内容。
需要了解两点:
- 先保存标签。 测试会根据保存的名称查找标签,因此全新的标签或未保存的重命名尚无法进行测试。在屏幕上的名称与已保存的名称匹配之前,按钮将保持灰色。
- 测试失败不会计入您的 Webhook 失败次数。 测试永远不会导致Webhook 可靠性中所述的重复失败后的自动关闭。
如果测试失败,系统会告知您的端点返回了什么信息(例如 404 或 500),这通常足以发现 URL 错误或工作流未开启等问题。
任务完成 Webhook
仅供参考。 任务 Webhook(作为数据)在此处为开发者记录;任务已创建、任务已更新和任务已完成事件与任何其他事件一样,可在 Webhook 表单的标准事件列表中选择 — 请参阅 可用触发事件 和 22 个 Webhook 事件。
当任务进入标记为完成阶段的阶段时,会发送此负载。在非完成阶段之间移动的任务将发送 taskUpdated 形状的负载。
事件名称
taskCompleted
触发时机
- 任务已更新。
- 其
stage值与之前的值相比发生了变化。 - 新阶段在账户的任务阶段设置中被配置为完成阶段。
有效载荷格式
{
"event": "taskCompleted",
"contact": {
"email": "jane@example.com",
"phone_number": "+15551234567",
"first_name": "Jane",
"last_name": "Smith",
"human_alerted": false,
"human_alert_reason": null
},
"user": {
"email": "owner@example.com",
"first_name": "Alex",
"last_name": "Doe"
},
"message": {
"id": "<task-id>",
"title": "Follow up with Jane",
"description": "Confirm pricing and send proposal",
"type": "follow_up",
"priority": "high",
"stage": "<stage-id>",
"due_date": "2026-01-20T15:00:00Z",
"source": "ai",
"source_detail": "<source-detail>",
"campaign_id": "<campaign-id>",
"linked_human_alert": "<human-alert-id>",
"tags": ["qualified-lead"],
"notes": "Customer requested a callback"
}
}
| 字段 | 描述 |
|---|---|
event |
此 Webhook 始终为 taskCompleted。当任务发生变更但未进入完成阶段时,发送的有效载荷格式与 taskUpdated 相同。 |
contact |
与任务关联的联系人(如有)。未关联时为 null。 |
contact.human_alert_reason |
联系人被标记为需要人工关注的原因(如适用)。 |
user |
拥有该任务的账户的基本身份信息。 |
message.id |
任务的唯一 ID。 |
message.title / description |
任务的标题和描述。 |
message.type |
任务类型(例如 follow_up、call、custom)。 |
message.priority |
任务优先级(low、medium、high)。 |
message.stage |
任务当前所处阶段的 ID。 |
message.due_date |
任务的截止日期(如已设置)。 |
message.source |
任务的创建方式(ai、manual、api)。 |
message.source_detail |
关于来源的额外详细信息。 |
message.campaign_id |
关联营销活动的 ID,或 null。 |
message.linked_human_alert |
关联的人工提醒 ID(如有)。 |
message.tags |
应用于任务的标签。 |
message.notes |
关于任务的自由格式备注。 |
关闭(或删除)Webhook
每个 Webhook 在其所在行都有一个开关。将其关闭会停止接收事件,但会保留您配置的所有内容——URL、事件、任何签名密钥。重新开启后,它将从中断处继续;关闭期间发生的任何事件都不会在之后补发。
当您希望暂时停止发送时使用此功能:例如您的端点正在重建、您正在调试一个嘈杂的集成,或者您正在暂停某个自动化流程。
删除 Webhook(点击其所在行的垃圾桶图标)会将其永久移除,包括其签名密钥。如果您只是想停止发送,请改用关闭开关——删除操作仅适用于您完全不再需要该端点的情况。
这与自动关闭的 Webhook 不同。 如果我们在多次失败后禁用了您的 Webhook(请参阅 Webhook 可靠性),上面的开关将无法将其恢复。一旦您的端点修复完毕,请编辑该 Webhook 并通过更改 URL 保存(任何 URL 更改都会重新启用它),或者通过 API 调用 重新启用端点 —— 您也可以联系支持团队,我们将为您重新开启。
签名有效载荷(验证 Webhook 是否确实来自我们)
任何获知您 Webhook URL 的人都可以向其发送伪造请求。如果您会自动处理 Webhook(例如更新账单、创建 CRM 记录),开启签名功能可以让您验证每个请求确实来自我们。
签名功能是可选的,默认关闭,您可以在每个 Webhook 的编辑视图中(打开已保存 Webhook 的所在行)单独开启。
开启签名
- 打开 Webhook(设置 → 集成 → Webhooks → 点击您的 Webhook 所在行)。
- 在 签名密钥 (Signing secret) 部分,点击 生成 (Generate)。
- 复制该密钥(它以
whsec_开头)并将其存储在您的接收系统中。请像对待密码一样妥善保管。
您可以随时回到此面板查看、复制、轮换或关闭该密钥。
我们发送的内容
一旦开启签名,每次 webhook 投递都会携带以下两个额外的 HTTP 标头:
| 标头 | 含义 |
|---|---|
X-Webhook-Signature |
签名,格式为 v1=<hex>。 |
X-Webhook-Timestamp |
我们发送的时间,以秒为单位的 Unix 时间戳。 |
无论是否签名,这三个标头都会出现在每次投递中:
| 标头 | 含义 |
|---|---|
X-Webhook-Delivery |
此事件的唯一 ID。在重试过程中保持不变,因此它是您进行去重的依据。 |
X-Webhook-Attempt |
这是第几次尝试(1 为第一次尝试)。 |
X-Webhook-Event |
事件名称,以便您无需读取正文即可进行路由。 |
如何验证
签名是对字符串 <timestamp>.<raw request body> 进行 HMAC-SHA256 计算的结果,并使用您的签名密钥作为密钥。
请针对原始请求正文进行验证——即您收到的确切字节。 如果您的框架在检查前解析了 JSON 并重新序列化,字节可能会发生变化,导致签名不匹配。
Node.js 示例:
const crypto = require("crypto");
function verify(rawBody, headers, secret) {
const timestamp = headers["x-webhook-timestamp"];
const signature = headers["x-webhook-signature"]; // "v1=<hex>"
// Reject anything older than 5 minutes so a captured request can't be replayed later.
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
return crypto.timingSafeEqual(Buffer.from(signature.replace("v1=", "")), Buffer.from(expected));
}
Python 示例:
import hashlib, hmac, time
def verify(raw_body: bytes, headers, secret: str) -> bool:
timestamp = headers["X-Webhook-Timestamp"]
signature = headers["X-Webhook-Signature"].replace("v1=", "")
# Reject anything older than 5 minutes so a captured request can't be replayed later.
if abs(time.time() - int(timestamp)) > 300:
return False
expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(signature, expected)
请使用时间恒定函数 (
timingSafeEqual/compare_digest) 来比较签名,而不是使用==。这样做无需额外成本,且能避免一类隐蔽的攻击。
轮换密钥
点击 轮换 (Rotate) 以替换密钥。切换是即时的:下一次投递将仅使用新密钥进行签名。如果您的端点处于在线状态,请在部署新密钥后的几分钟内同时接受旧密钥和新密钥。
关闭签名功能只会停止发送签名请求头。
重试失败的投递
默认情况下,失败的投递不会重试——如果您的系统在那个时刻宕机,该事件就会丢失。
在 Webhook 上开启 重试失败的投递(在创建/编辑表单中),我们将持续尝试:
| 尝试次数 | 时间 |
|---|---|
| 1 | 立即 |
| 2 | 1 分钟后 |
| 3 | 5 分钟后 |
| 4 | 30 分钟后 |
| 5 | 2 小时后 |
这跨越了大约 2 小时 40 分钟,因此 Webhook 可以度过您的维护窗口或短暂的服务中断。
会重试的情况: 临时性问题——您的服务器返回 5xx 错误、超时或连接失败。
不会重试的情况: 如果您的端点本身拒绝了请求(任何 4xx 错误),我们不会重试——再次发送完全相同的请求只会导致相同的拒绝。
哪些事件会重试: 标签 webhook (contact_tags_updated)、三个任务事件以及每日摘要。其余事件仅发送一次,因此对于这些事件,开关不起作用。每个事件仍然携带 X-Webhook-Delivery,因此一条去重规则即可覆盖所有事件。
仅在您的端点支持幂等性时开启重试。 重试意味着同一个事件可能会多次到达。请使用
X-Webhook-Delivery标头来识别重复项:它在同一事件的每次尝试中保持不变,因此您可以安全地忽略已经处理过的 ID。
重试机制与重复失败后的自动关闭功能(请参阅 Webhook 可靠性)的交互方式符合您的预期:失败计数器仅在所有重试次数用尽后才计算整个交付,而不是针对每次单独的尝试。
Webhook 可靠性
- Your AI Connector 通过安全连接 (HTTPS) 发送 Webhook。请确保您提供的 Web 地址使用 HTTPS。
- 如果您的系统返回错误,则视为投递失败。
- 监控接收系统的正常运行时间,以避免错过事件。
- 对于关键工作流,请开启 重试失败的投递,并考虑设置备用机制。
Webhook 在多次失败后会自动关闭。 如果您的 Webhook URL 反复失败(连续约 5 次错误,或配置类错误连续 3 次),Your AI Connector 将自动停止向该 URL 发送事件。当您的端点恢复正常后,若要重新启用:请编辑该 Webhook 并通过更改 URL 保存(任何 URL 更改都会重新启用它),或者通过 API 使用 重新启用端点 —— 仅使用相同的 URL 重新保存是不够的。支持团队也可以为您重新启用。
故障排除
| 问题 | 解决方案 |
|---|---|
| Webhook 未触发 | 首先检查 Webhook 在其行中是否未被关闭。然后确认已选择正确的事件,并且您的 URL 可以从互联网访问。 |
| 测试事件有效但实际事件无效 | 确保已启用特定的事件类型。如果您期望在应用标签时收到请求,请注意 subscribed_to_tags 不会将 Webhook 的事件范围限定为某个标签 — 它仅缩小了哪些标签会生成对话摘要通知。若要在应用特定标签时获取请求,请在座席(或营销活动)的标签选项卡中设置 Webhook URL — 请参阅 联系人标签更新 Webhook。 |
| n8n / Make / Zapier 中未收到任何内容 | 您可能正在使用该平台的测试 URL,它仅在点击“监听测试事件”后监听单个事件。对于实时事件,请保存生产 URL 并将工作流切换为激活状态。 |
| 收到重复事件 | 检查是否有多个 Webhook 指向同一个 URL。如果启用了重试失败的交付,则每当您的端点接受了事件但未及时响应时,就会出现重复 — 请在 X-Webhook-Delivery 上进行去重。 |
| 签名检查总是失败 | 几乎总是因为主体在检查前被重新序列化了。请根据原始请求主体进行验证,对 <timestamp>.<body> 进行签名,如果您最近轮换过密钥,请确认您使用的是当前的密钥。 |
| 未进行重试 | 除非在特定的 Webhook 上启用,否则不会进行重试。我们不会重试 4xx 响应。 |
campaign 块总是 null |
如果您的账户使用座席,这是预期的:联系人归属于座席而不是营销活动。请阅读 agent 块 — 请参阅 Webhook 数据格式。 |
| 数据为空或格式错误 | 验证您的接收系统是否接受 JSON。检查您的服务器日志以查找解析错误。 |
| Webhook URL 返回错误 | 使用 Postman 或 webhook.site 等工具测试您的 URL。 |
| Webhook 在中断后完全停止触发 | 重复失败会自动禁用 Webhook。重新保存不会重新启用它 — 请修复您的端点,然后联系支持人员。 |
| 保存或测试时出现权限错误 | 您需要“集成”的“编辑”权限。请要求账户所有者授予该权限。 |
Webhook 的 subscribed_to_tags 列表返回为空 |
subscribed_to_tags 不会将 Webhook 的事件范围限定为某个标签 — 它仅缩小了哪些标签会生成对话摘要通知。从 Webhook 表单进行编辑不再会清除该列表(2026 年 7 月 21 日已修复)。如果 Webhook 在该日期之前丢失了列表,请通过 Webhooks API 重新设置 subscribed_to_tags — 请参阅 基于标签的 Webhook 触发器。 |
后续步骤
- GoHighLevel 集成 — 使用 Webhook 将 Your AI Connector 与 GHL 集成。
- API 访问 — 将 Webhook 与 API 结合使用,实现强大的自动化功能。
- 使用标签标记联系人 — 设置触发 Webhook 的标签。