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

# Webhook 重试机制

> 启润支付如何重试失败的 Webhook 投递

如果你的 Webhook 端点未返回 `2xx` 状态码，启润支付将自动重试投递。

## 重试计划

启润支付最多重试 **7 次**：

| 重试次数    | 失败后等待时间 |
| ------- | ------- |
| 第 1 次重试 | 30 秒    |
| 第 2 次重试 | 30 秒    |
| 第 3 次重试 | 1 分钟    |
| 第 4 次重试 | 1 分钟    |
| 第 5 次重试 | 30 分钟   |
| 第 6 次重试 | 30 分钟   |
| 第 7 次重试 | 30 分钟   |

7 次重试失败后，Webhook 将被标记为**失败**，不再继续重试。

## 什么算作失败

以下情况 Webhook 投递被视为失败：

* 你的端点返回非 `2xx` HTTP 状态码（如 `400`、`500`）
* 你的端点在 **30 秒**内未响应
* 无法连接到你的服务器（DNS 错误、连接被拒绝、超时）

<Info>
  `2xx` 响应（如 `200`、`201`、`204`）即被视为投递成功，不论响应体内容如何。
</Info>

## 处理重试

由于 Webhook 可能被重试，你的端点应该是**幂等的** — 多次处理同一事件应产生相同的结果。

### 使用事件 ID 去重

每个 Webhook 事件都有唯一的 `id` 字段。存储已处理的事件 ID 并跳过重复事件：

```javascript theme={null}
const processedEvents = new Set(); // 生产环境请使用数据库

app.post('/webhooks/kyren', (req, res) => {
  // ... 验证签名 ...

  const event = JSON.parse(req.body.toString());

  // 检查是否已处理过此事件
  if (processedEvents.has(event.id)) {
    console.log(`重复事件 ${event.id}，跳过`);
    return res.status(200).send('OK');
  }

  // 处理事件
  processEvent(event);

  // 标记为已处理
  processedEvents.add(event.id);

  res.status(200).send('OK');
});
```

<Tip>
  在生产环境中，将已处理的事件 ID 存储在数据库（如 Redis 或你的主数据库）中，而不是内存中。
</Tip>

### 快速返回 200

收到并验证 Webhook 后立即返回 `200` 响应。如果处理需要较长时间，请异步执行：

```javascript theme={null}
app.post('/webhooks/kyren', (req, res) => {
  // ... 验证签名 ...

  const event = JSON.parse(req.body.toString());

  // 立即响应
  res.status(200).send('OK');

  // 异步处理
  processEventAsync(event).catch(err => {
    console.error('处理事件失败:', err);
  });
});
```

## 监控 Webhook 投递

排查投递问题时，请将 Kyren Webhook 事件与你自己的服务端日志对照。请记录：

* 你配置的 Webhook URL
* 事件类型和订单号
* 你的服务端收到请求的时间
* 你的服务端返回的响应码或错误

如果需要 Kyren 协助检查投递尝试，请带上这些信息联系支持。

## 故障排除

| 问题          | 解决方案                      |
| ----------- | ------------------------- |
| 未收到 Webhook | 检查 Webhook URL 是否正确且可公开访问 |
| 签名验证失败      | 确保使用原始请求体（未解析的 JSON）进行验证  |
| 频繁超时        | 立即返回 `200`，异步处理事件         |
| 重复事件        | 使用事件 `id` 字段实现幂等性         |
