> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 配置 Webhook 通知

> 在支付成功、订阅续费或退款处理时自动接收通知

## 什么是 Webhook？

Webhook 是 Waffo Pancake 在事件发生时自动发送到你服务器的通知 — 支付成功、订阅续费、退款处理等。

**为什么需要 Webhook：**

* **自动化交付**：支付后立即发送下载链接或授予访问权限
* **保持系统同步**：订阅状态变化时更新你的数据库
* **实时响应**：处理失败支付、取消和退款等事件

***

## 第一步：在 Dashboard 中添加 Webhook

<Steps>
  <Step title="进入设置">
    在 Dashboard 中，导航到 **设置 → Webhooks**。

    <Frame>
      <img src="https://mintcdn.com/waffo/MyxWRBeTICeW5ClC/images/guides/webhook-settings.png?fit=max&auto=format&n=MyxWRBeTICeW5ClC&q=85&s=ebf0fc610d7a43a1578dca3607e5f324" alt="Webhooks 设置页面，分为 Test Mode 和 Live Mode 两个区域" width="2000" height="1140" data-path="images/guides/webhook-settings.png" />
    </Frame>
  </Step>

  <Step title="选择格式">
    选择负载（payload）发送到目标平台时的格式 —— 自有后端用 Raw JSON，使用聊天平台格式（Slack / Discord / 飞书 / Telegram）让消息原生地呈现在该工具中，或选择 **OpenClaw / Hermes**（自托管的 Pancake 插件）做自定义路由与下游处理。详见下方 [选择负载格式](#选择负载格式)。

    <Frame>
      <img src="https://mintcdn.com/waffo/MyxWRBeTICeW5ClC/images/guides/webhook-add-format.png?fit=max&auto=format&n=MyxWRBeTICeW5ClC&q=85&s=69333c1c37cae6513c9574f502c69000" alt="添加 Webhook 弹窗中展开的 Format 下拉菜单：Raw / Feishu / Slack / Discord / Telegram / OpenClaw·Hermes" width="2000" height="1140" data-path="images/guides/webhook-add-format.png" />
    </Frame>
  </Step>

  <Step title="设置 Webhook URL">
    输入 Waffo Pancake 发送事件通知的目标 URL。

    * **测试模式 URL**：你的开发/预发布服务器（如 `https://staging.yoursite.com/webhooks/waffo`）
    * **生产环境 URL**：你的生产服务器（如 `https://yoursite.com/webhooks/waffo`）

    <Tip>
      你可以为测试和生产环境设置不同的 URL，这样测试事件和真实事件就不会混在一起。
    </Tip>

    <Note>
      如果上一步选了 **Telegram**，这里要填的是 **Bot Token** 和 **Chat ID**，而不是 URL。获取方法见下方 [Telegram](#telegram) 章节。
    </Note>
  </Step>

  <Step title="选择事件">
    默认订阅所有事件，取消勾选你不需要的事件即可。
  </Step>

  <Step title="保存">
    点击 **Save Webhook** 保存。
  </Step>
</Steps>

每个环境最多可以配置 **10 个 Webhook**，因此你可以把同一组事件分发到多个目标（你的后端、Slack 频道、内部仪表盘等），无需自行编写转发服务。同一环境下不允许重复添加相同的 URL。

<Note>
  **生产环境提示**：生产模式的 Webhook 只在店铺通过审核后才会真正投递。审核期间请使用测试模式 Webhook 配合预发布代码进行验证。
</Note>

***

## 选择负载格式

Waffo 可以按照目标平台期望的格式投递事件，你不需要自己写转换器。在添加 Webhook 时选择格式即可；如果之后想换格式，重新添加一个 Webhook 即可。

| 格式                    | 适用场景                                 | Endpoint                                                 |
| --------------------- | ------------------------------------ | -------------------------------------------------------- |
| **Raw**（默认）           | 调用自己的后端，期望拿到带签名的标准 JSON 负载。          | 任意 HTTPS URL                                             |
| **飞书 / Lark**         | 通过自定义机器人把事件推送到飞书群。                   | `https://open.feishu.cn/open-apis/bot/v2/hook/<hook-id>` |
| **Slack**             | 通过 Incoming Webhook 把事件推送到 Slack 频道。 | `https://hooks.slack.com/services/T.../B.../<token>`     |
| **Discord**           | 通过频道 Webhook 把事件推送到 Discord 频道。      | `https://discord.com/api/webhooks/<id>/<token>`          |
| **Telegram**          | 通过机器人把事件推送到 Telegram 聊天或群组。          | Bot Token + Chat ID（URL 由 Waffo 自动拼接）                    |
| **OpenClaw / Hermes** | 通过自托管的 **Pancake 插件** 路由事件，做自定义下游处理。 | `https://relay.waffo.ai/webhook/<webhook-id>`            |

只有 **Raw** 格式带 RSA-SHA256 签名。聊天平台格式通过 URL 中嵌入的 token 认证（由对应平台签发），因此不使用签名校验。

### Raw

1. 在你的后端暴露一个接受 `POST application/json` 的 HTTPS 端点。
2. 把 URL 粘贴到 **Endpoint URL** 字段。
3. 在 **设置 → Webhooks** 页面直接复制 **Webhook Public Key**（验签公钥）—— 选择你正在对接的环境（Test 或 Production），用它来验签（见 [API Reference — Webhooks](/api-reference/webhooks)）。该公钥为**平台级，所有门店共用**，与你刚添加的 Webhook 无关；新增、修改、删除 Webhook URL 都不会改变它。

### 飞书 / Lark

1. 在飞书群里添加一个 **自定义机器人**，复制它的 Webhook URL。
2. URL 形如 `https://open.feishu.cn/open-apis/bot/v2/hook/<hook-id>`（海外区域是 `open.larksuite.com/...`，两者都能用）。
3. 把 URL 粘贴到 **Endpoint URL** 字段。

### Slack

1. 在 Slack 工作区里为目标频道安装一个 **Incoming Webhook**。
2. 复制 Webhook URL，形如 `https://hooks.slack.com/services/T.../B.../<token>`。
3. 把 URL 粘贴到 **Endpoint URL** 字段。

### Discord

1. 在目标频道里打开 **编辑频道 → 整合 → Webhook → 新建 Webhook**，复制 URL。
2. 格式：`https://discord.com/api/webhooks/<id>/<token>`。
3. 把 URL 粘贴到 **Endpoint URL** 字段。

### Telegram

Telegram 需要 **Bot Token** 和 **Chat ID** 两个值 —— Waffo 会自动为你拼出 Telegram 的 `sendMessage` URL。

1. 与 [@BotFather](https://t.me/botfather) 对话，创建（或选用）一个机器人，复制它的 token，形如 `123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11`。
2. 把机器人加进目标聊天或频道，并授予它发送消息的权限。
3. 获取 Chat ID。最简单的办法：在该聊天里发一条消息，然后访问 `https://api.telegram.org/bot<TOKEN>/getUpdates`，从响应里复制 `chat.id`。
4. 在 **添加 Webhook** 的弹窗里选择 **Telegram**，填入 **Bot Token** 和 **Chat ID** 后保存。

底层 Waffo 会向 `https://api.telegram.org/bot<TOKEN>/sendMessage` 发起请求，并把 `chat_id` 设为你提供的值。

### OpenClaw / Hermes（Pancake 插件）

Pancake 插件是 Waffo 的自托管中继：从 Waffo 接收事件，运行你的自定义逻辑（模板渲染、限流、多目标分发），再转发到任意位置。**OpenClaw** 和 **Hermes** 是该插件的两种开箱即用形态，选你的技术栈匹配的那个即可。

1. 用对应的命令安装插件：

   ```bash theme={"system"}
   # OpenClaw
   npx -p @waffo/pancake-plugin openclaw-setup

   # Hermes
   npx -p @waffo/pancake-plugin hermes-setup
   ```

   完整安装指南：[github.com/waffo-com/waffo-pancake-plugin](https://github.com/waffo-com/waffo-pancake-plugin)。

2. 安装后插件会给你一个形如 `https://relay.waffo.ai/webhook/<webhook-id>` 的中继 URL。

3. 在 **添加 Webhook** 弹窗里选择 **OpenClaw / Hermes**，粘贴中继 URL 并保存。

***

## 第二步：了解事件类型

Waffo Pancake 会发送以下 Webhook 事件：

### 订单事件

| 事件                | 触发时机 | 常见操作        |
| ----------------- | ---- | ----------- |
| `order.completed` | 订单完成 | 交付商品、授予访问权限 |

### 订阅事件

| 事件                               | 触发时机    | 常见操作        |
| -------------------------------- | ------- | ----------- |
| `subscription.activated`         | 订阅已激活   | 创建账户、设置限额   |
| `subscription.payment_succeeded` | 订阅扣款成功  | 延长访问期限      |
| `subscription.updated`           | 订阅详情变更  | 更新访问级别      |
| `subscription.canceling`         | 已请求取消   | 通知团队、发送挽留优惠 |
| `subscription.uncanceled`        | 订阅已重新激活 | 恢复完整访问      |
| `subscription.canceled`          | 订阅完全终止  | 撤销访问        |
| `subscription.past_due`          | 付款失败    | 通知客户、重试     |

### 退款事件

| 事件                 | 触发时机   | 常见操作      |
| ------------------ | ------ | --------- |
| `refund.succeeded` | 退款处理成功 | 撤销访问、更新记录 |
| `refund.failed`    | 退款处理失败 | 通知商户、调查原因 |

***

## 第三步：配置邮件通知

除了 Webhook 事件，你还可以为自己和客户配置邮件通知。

### 商户通知

进入 **设置 → 通知** 选择哪些事件触发给你的邮件提醒：

* 新订单
* 新订阅
* 支付失败
* 退款请求

<Frame>
  <img src="https://mintcdn.com/waffo/5dRlk76Jm-9Zm6Tj/images/guides/notification-settings.png?fit=max&auto=format&n=5dRlk76Jm-9Zm6Tj&q=85&s=c1e650a73ceae7f9ee34289cc7efb9c4" alt="通知设置" width="1440" height="900" data-path="images/guides/notification-settings.png" />
</Frame>

### 客户通知

客户会自动收到以下事件的邮件：

* 订单确认
* 订阅确认
* 订阅续费
* 订阅取消
* 支付失败

你可以在通知设置中开关这些选项。

***

## Webhook 工作原理

```
事件发生（如支付成功）
    ↓
Waffo Pancake 向你的 Webhook URL 发送 POST 请求
    ↓
你的服务器接收事件
    ↓
你的服务器处理事件（交付商品、更新数据库等）
    ↓
你的服务器返回 200 OK
```

### 重试策略

如果你的服务器没有返回 2xx 状态码，Waffo Pancake 会重试：

| 重试次数    | 延迟    |
| ------- | ----- |
| 第 1 次重试 | 5 分钟  |
| 第 2 次重试 | 30 分钟 |
| 第 3 次重试 | 2 小时  |
| 第 4 次重试 | 8 小时  |
| 第 5 次重试 | 24 小时 |

5 次重试都失败后，该事件将被标记为失败。

***

## 开发者：代码集成

如果你要将 Webhook 与服务器集成，流程如下：

### 1. 创建 Webhook 端点

你的服务器需要一个 POST 端点来接收事件。具体实现取决于你的技术栈。

### 2. 验证签名

每个 Webhook 请求都包含签名头用于安全验证。验证签名以确保请求来自 Waffo Pancake 而非恶意第三方。

### 3. 处理事件

解析事件类型和数据，然后执行相应操作（交付商品、更新订阅状态等）。

### 4. 快速响应

尽快返回 200 状态码。如果需要执行重量级处理，在响应之后异步执行。

<Note>
  详细的代码示例和签名验证说明，请参考 [API 参考 — Webhooks](/zh/api-reference/webhooks)。
</Note>

***

## 测试 Webhook

<Steps>
  <Step title="设置测试 Webhook URL">
    在 Dashboard → 设置 → Webhooks 中，输入你的测试服务器 URL。
  </Step>

  <Step title="创建测试购买">
    使用测试模式进行一笔购买。这会向你的测试 URL 触发 Webhook 事件。
  </Step>

  <Step title="验证接收">
    检查你的服务器日志，确认 Webhook 已被正确接收和处理。
  </Step>
</Steps>

***

## 使用 ngrok 进行本地开发

在本地开发 webhook 处理器时，Pancake 服务器无法直接访问 `http://localhost:3000`。你需要一个**公网 HTTPS 隧道**把外部请求转发到本地端口。我们推荐 [ngrok](https://ngrok.com) —— 开发用免费，且会保留所有自定义请求头（包括 `X-Waffo-Signature`）。

### 为什么必须用隧道

Webhook 投递是**入站**到你的服务器：Pancake 主动 POST 到你配置的 URL。localhost 地址只能在你本机访问，没有隧道这些请求根本到达不了。隧道为你的本地服务在开发期间提供一个公网可达的 HTTPS 主机名。

### 安装并启动 ngrok

<Steps>
  <Step title="安装">
    * **macOS**：`brew install ngrok`
    * **Windows / Linux**：从 [ngrok.com/download](https://ngrok.com/download) 下载
  </Step>

  <Step title="登录授权（免费层即可）">
    在 [ngrok.com](https://ngrok.com) 注册账号，从 dashboard 复制 authtoken，然后运行：

    ```bash theme={"system"}
    ngrok config add-authtoken <your-authtoken>
    ```
  </Step>

  <Step title="启动隧道">
    把 ngrok 指向本地服务的端口。如果你的 webhook handler 跑在 `localhost:3000`：

    ```bash theme={"system"}
    ngrok http 3000
    ```

    ngrok 会输出类似：

    ```
    Forwarding  https://abc-123-456-789.ngrok-free.app -> http://localhost:3000
    ```

    复制 `https://...ngrok-free.app` 这个 URL —— 这就是你的公网 webhook 端点。
  </Step>
</Steps>

### 接入 Pancake

<Steps>
  <Step title="配置 Test Webhook URL">
    在商户控制台进入对应店铺，前往 **Settings → Webhooks**。把 ngrok URL（追加你的 handler 路径，如 `https://abc-123.ngrok-free.app/api/webhooks/waffo`）填入 **Test Webhook URL**，勾选要接收的事件，保存。

    <Warning>
      只在 Test 环境用 ngrok URL。**绝对不要**把临时隧道 URL 放进 Production webhook —— 生产流量必须打到一个稳定的、已部署的端点。
    </Warning>
  </Step>

  <Step title="触发事件">
    可以在控制台点 **Send test event**，或者在 test mode 下做一笔真实操作（例如创建收银台并用[测试卡](/zh/api-reference/webhooks#testing)完成支付）。
  </Step>

  <Step title="检查请求">
    打开 ngrok 自带的本地 web inspector：[http://127.0.0.1:4040](http://127.0.0.1:4040) —— 它会展示每一条经过的请求,包括 headers 和 body。确认 `X-Waffo-Signature` 这个 header 存在。
  </Step>

  <Step title="在 handler 中验签">
    查看本地服务日志,应该能看到 webhook POST 进来,`verifyWebhook()` 验签通过。如果验签失败,看下面的常见踩坑。
  </Step>
</Steps>

### 常见踩坑

| 现象                       | 原因                                                                    | 解决方案                                                        |
| ------------------------ | --------------------------------------------------------------------- | ----------------------------------------------------------- |
| **localtunnel 始终验签 401** | localtunnel 会**剥离**自定义 HTTP 请求头,导致 `X-Waffo-Signature` 永远到达不了 handler | 改用 ngrok 或 cloudflared —— 两者都保留所有 header                    |
| **重启 ngrok 后 URL 变了**    | 免费层每次 `ngrok http` 都会分配一个新的随机子域名                                      | 每次重启都要回控制台更新 Test Webhook URL。频繁联调可考虑 ngrok 付费层的固定子域名       |
| **隔一段时间事件不来了**           | 免费 ngrok 会话有几小时上限会自动断开                                                | 重启 `ngrok http 3000` 并重新粘贴新 URL                             |
| **同一事件 Pancake 重发了多次**   | 你的 handler 返回了非 2xx,Pancake 按指数退避策略重试                                 | 修复 handler,然后等下次重试,或在控制台 webhook delivery log 中点 **Resend** |

### 替代方案：Cloudflared

如果你偏好不需要注册账号的方案,[cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) 用法类似：

```bash theme={"system"}
cloudflared tunnel --url http://localhost:3000
```

它同样保留 header,临时隧道无需注册,会输出 `*.trycloudflare.com` 形式的 URL 直接粘到控制台即可。代价是没有内置请求 inspector UI —— 你只能靠自己的服务日志排查。

### 联调自检清单

* [ ] 本地服务已启动并监听预期端口
* [ ] `ngrok http <port>` 在跑,forwarding URL 已记下
* [ ] 控制台的 Test Webhook URL 是**当前**的 ngrok URL（含 handler 路径）
* [ ] 在 [http://127.0.0.1:4040](http://127.0.0.1:4040) 看到入站请求,带 `X-Waffo-Signature` header
* [ ] 本地日志显示 `verifyWebhook` 验签成功并触发了事件 handler

***

## 最佳实践

1. **快速响应**：立即返回 200，异步处理业务逻辑
2. **处理重复**：事件可能被发送多次 — 确保你的处理是幂等的
3. **验证签名**：处理前始终验证 Webhook 签名
4. **记录日志**：保留收到的 Webhook 日志用于调试
5. **监控失败**：在 Dashboard 中检查失败的 Webhook 投递

***

## 检查清单

* [ ] 测试和生产环境的 Webhook URL 已配置
* [ ] 团队的邮件通知已配置
* [ ] 客户通知偏好已设置
* [ ] 测试 Webhook 已成功接收和处理
* [ ] 签名验证已实现（如使用代码集成）

***

## 下一步

<CardGroup cols={2}>
  <Card title="管理退款" icon="rotate-left" href="/zh/guides/refunds">
    处理退款请求并跟踪退款状态
  </Card>

  <Card title="API 参考 — Webhooks" icon="code" href="/zh/api-reference/webhooks">
    详细的 Webhook 负载格式和代码示例
  </Card>
</CardGroup>
