> ## 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.

# Webhooks

> 接收和处理实时事件通知

## 概览

Webhooks 将事件实时推送到您的服务器，无需轮询。

```
Waffo Pancake 中发生事件 --> HTTP POST 到您的端点 --> 您处理事件
```

***

## 设置

<Steps>
  <Step title="创建 HTTPS 端点">
    构建一个可公开访问的端点，接受 POST 请求并返回 200 OK。
  </Step>

  <Step title="在控制台中注册">
    前往控制台 > API 与开发 > Webhooks。添加您的端点 URL。
  </Step>

  <Step title="选择事件">
    选择需要接收的事件类型。
  </Step>

  <Step title="保存">
    保存您的 Webhook 配置。
  </Step>
</Steps>

***

## 事件类型

事件涵盖支付、订阅和退款生命周期通知。在控制台中配置 Webhooks 时，您可以选择要订阅的事件类别。

<Note>
  具体的事件名称和可用类别会在您配置 Webhook 端点时显示在控制台中。请参阅您的控制台以获取最新列表。
</Note>

***

## 载荷格式

每次 Webhook 投递都是一个 HTTP POST 请求，JSON 请求体包含事件类型和关联数据：

```json theme={"system"}
{
  "event": "<event_type>",
  "data": {
    // 事件相关字段
  }
}
```

<Note>
  所有 ID 为 UUID v4 格式。金额以显示格式字符串表示（例如，"29.00" = \$29.00）。时间戳为 ISO 8601 UTC 格式。
</Note>

***

## 处理 Webhooks

快速返回 `200 OK`。如果处理逻辑较重，请异步处理。

<CodeGroup>
  ```javascript Node.js (Express) theme={"system"}
  app.post('/webhooks/waffo', (req, res) => {
    // 立即响应
    res.status(200).send('OK');

    // 异步处理
    const { event, data } = req.body;

    switch (event) {
      case 'order.completed':
        handleOrderCompleted(data);
        break;
      case 'subscription.activated':
        handleSubscriptionActivated(data);
        break;
      case 'subscription.canceled':
        handleSubscriptionCanceled(data);
        break;
    }
  });
  ```

  ```python Python (Flask) theme={"system"}
  from flask import Flask, request, jsonify

  app = Flask(__name__)

  @app.route('/webhooks/waffo', methods=['POST'])
  def handle_webhook():
      payload = request.get_json()
      event = payload.get('event')
      data = payload.get('data')

      if event == 'order.completed':
          handle_order_completed(data)
      elif event == 'subscription.activated':
          handle_subscription_activated(data)

      return jsonify({'received': True}), 200
  ```
</CodeGroup>

***

## 幂等性

事件可能会被重复投递。使用事件数据进行去重：

```javascript theme={"system"}
const processedEvents = new Set();

app.post('/webhooks/waffo', (req, res) => {
  const { event, data } = req.body;
  const eventKey = `${event}:${data.id}`;

  if (processedEvents.has(eventKey)) {
    return res.status(200).send('Already processed');
  }

  processedEvents.add(eventKey);
  res.status(200).send('OK');
  processWebhook(event, data);
});
```

<Tip>
  在生产环境中，请将已处理的事件 ID 存储到数据库中，而非内存中，以确保服务器重启后数据不丢失。
</Tip>

***

## 重试策略

投递失败后会自动重试。请确保您的端点及时返回 `200` 状态码以确认收到。

***

## 测试

使用[测试模式](/zh/features/test-mode)测试 Webhooks：

1. 在控制台中切换到测试模式
2. 前往开发者 > Webhooks
3. 执行会触发事件的操作
4. 检查您的端点是否收到了事件

<Note>
  Webhooks 在测试模式和正式模式中都会触发。请确保您的端点能够区分不同环境。
</Note>

***

## 最佳实践

1. **使用 HTTPS** -- 生产环境的 Webhook 端点必须使用 HTTPS
2. **快速响应** -- 在 30 秒内返回 200
3. **处理重复投递** -- 使用 ID 进行去重
4. **异步处理** -- 不要让耗时操作阻塞响应
5. **记录所有日志** -- 记录收到的 Webhook 以便调试
