## 4. 事件系统

### 4.1 Webhook 配置

SyncBridge 通过 Webhook 向合作伙伴实时推送事件。合作伙伴必须注册 Webhook 端点，并配置所需接收的事件类型。

#### 4.1.1 注册 Webhook

```
POST /webhooks
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "url": "https://partner.example.com/hooks/syncbridge",
  "events": [
    "entity.created",
    "entity.updated",
    "entity.deleted",
    "sync.completed",
    "sync.failed",
    "schema.updated"
  ],
  "secret": "whsec_a1b2c3d4e5f6",
  "metadata": {
    "environment": "production",
    "team": "integrations"
  }
}
```

**响应**：

```json
{
  "webhook_id": "wh_9f8e7d6c",
  "status": "active",
  "created_at": "2026-04-10T10:00:00Z",
  "test_url": "https://api.syncbridge.io/webhooks/wh_9f8e7d6c/test"
}
```

#### 4.1.2 Webhook 载荷格式

所有 Webhook 投递均采用统一的信封格式：

```json
{
  "event_id": "evt_abc123",
  "event_type": "entity.updated",
  "timestamp": "2026-04-10T10:15:00Z",
  "webhook_id": "wh_9f8e7d6c",
  "data": {
    "entity_id": "ent_001",
    "entity_type": "contact",
    "changes": {
      "email": {
        "old": "alice@old.com",
        "new": "alice@example.com"
      }
    }
  },
  "metadata": {
    "delivery_attempt": 1,
    "correlation_id": "corr_xyz789"
  }
}
```

#### 4.1.3 Webhook 签名验证

每次 Webhook 投递都会在请求头中附带 `X-SyncBridge-Signature`，其值为使用 Webhook 密钥计算的 HMAC-SHA256 签名。合作伙伴在处理任何 Webhook 载荷之前，必须验证该签名。

```python
import hmac
import hashlib

def verify_signature(payload_body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode('utf-8'),
        payload_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(f"sha256={expected}", signature)
```

### 4.2 事件投递与重试

SyncBridge 对投递失败的 Webhook 采用指数退避策略：

| 尝试次数 | 延迟时间 | 累计时间 |
|---------|---------|---------|
| 1 | 立即 | 0 |
| 2 | 30 秒 | 30s |
| 3 | 2 分钟 | 2m 30s |
| 4 | 15 分钟 | 17m 30s |
| 5 | 1 小时 | 1h 17m 30s |
| 6 | 4 小时 | 5h 17m 30s |
| 7（最终） | 12 小时 | 17h 17m 30s |

7 次尝试全部失败后，事件将被转移至死信队列（Dead-Letter Queue）。合作伙伴可通过仪表盘或 API 重放死信队列中的事件。

**投递成功**：合作伙伴端点在 30 秒内返回 HTTP 2xx。
**投递失败**：返回非 2xx 响应、请求超时或连接错误。

### 4.3 事件订阅管理

合作伙伴可以动态管理事件订阅，无需重新注册 Webhook。

```
PATCH /webhooks/{webhook_id}/subscriptions
Authorization: Bearer {access_token}
Content-Type: application/json

{
  "add": ["batch.started", "batch.progress"],
  "remove": ["sync.failed"]
}
```

---

## 5. 速率限制

### 5.1 限制规格

SyncBridge 对合作伙伴 API 调用执行以下速率限制：

| 套餐等级 | 请求数/分钟 | 突发量 | 最大并发连接数 |
|---------|-----------|-------|-------------|
| Standard | 600 | 100 | 50 |
| Premium | 3000 | 500 | 200 |
| Enterprise | 12000 | 2000 | 1000 |

每次 API 响应均通过请求头返回当前速率限制信息：

```
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 542
X-RateLimit-Reset: 1712736000
X-RateLimit-Retry-After: 0
```

### 5.2 速率限制的处理

触发速率限制时，API 返回 HTTP 429，并附带 `Retry-After` 请求头，指明合作伙伴可以重试的时间。合作伙伴必须实现退避逻辑，不应立即重试。

**速率限制响应**：

```json
{
  "error": {
    "code": "RATE_LIMITED",
    "message": "Rate limit exceeded. Please retry after the specified time.",
    "retry_after_seconds": 12,
    "limit": 600,
    "window": "1m"
  }
}
```

### 5.3 速率限制最佳实践

1. **实现客户端速率追踪**：持续监控 `X-RateLimit-Remaining` 请求头，在触及限制前主动降低请求频率。
2. **使用批量端点**：优先使用批次操作，而非单条实体请求，以减少 API 调用次数。
3. **缓存令牌响应**：访问令牌有效期为 1 小时——不应为每次 API 调用都申请新令牌。
4. **使用 Webhook 事件**：以 Webhook 事件接收实时变更通知，替代轮询方式。

---

## 6. 错误处理

### 6.1 错误响应格式

所有 API 错误均遵循统一的 JSON 结构：

```json
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description",
    "details": {
      "field": "data.email",
      "constraint": "format",
      "expected": "valid email address"
    },
    "request_id": "req_abc123",
    "documentation_url": "https://docs.syncbridge.io/errors/ERROR_CODE"
  }
}
```

### 6.2 错误码

| 错误码 | HTTP 状态码 | 说明 | 可重试？ |
|-------|-----------|-----|--------|
| `AUTHENTICATION_FAILED` | 401 | 令牌无效或已过期 | 是（刷新令牌后重试） |
| `AUTHORIZATION_DENIED` | 403 | 权限范围不足 | 否 |
| `NOT_FOUND` | 404 | 资源不存在 | 否 |
| `VALIDATION_FAILED` | 422 | 请求体验证失败 | 否（修正载荷后重试） |
| `RATE_LIMITED` | 429 | 超出速率限制 | 是（延迟后重试） |
| `CONFLICT` | 409 | 并发修改冲突 | 是（获取最新数据后重试） |
| `IDEMPOTENCY_CONFLICT` | 409 | 幂等键被不同载荷重复使用 | 否 |
| `BATCH_TOO_LARGE` | 413 | 批次超出最大限制（1000 个实体） | 否（缩减批次后重试） |
| `SCHEMA_MISMATCH` | 422 | 实体数据与已注册 Schema 不符 | 否（修正数据或 Schema 后重试） |
| `UPSTREAM_ERROR` | 502 | 上游系统不可用 | 是（退避后重试） |
| `SERVICE_UNAVAILABLE` | 503 | SyncBridge 维护中 | 是（延迟后重试） |
| `TIMEOUT` | 504 | 请求处理超时 | 是 |

### 6.3 幂等性

所有变更类端点均通过 `X-SyncBridge-Idempotency-Key` 请求头支持幂等操作。合作伙伴应为每个逻辑操作生成唯一的 UUID 并随请求一并提交。若以相同的幂等键发送完全相同的载荷，SyncBridge 将直接返回原始响应，不再重复处理。若载荷不同，则返回 `409 IDEMPOTENCY_CONFLICT` 错误。
