为 AI API 经销商构建合作伙伴 API Webhook:签名事件、持久交付和安全重播
可靠的合作伙伴 API webhook 的实用架构,涵盖提交的事件生成、租户安全扇出、签名、重试、重播、SSRF 保护、架构演变和协调。
轮询合作伙伴 API 来了解每个余额、客户、密钥、预算和使用情况的变化,这会造成一个尴尬的控制循环:重要的操作迟到,重复获取未更改的资源,并且可以以错误的顺序观察到并发更新。出站 Webhook 可以减少延迟,但前提是它们构建为持久的通知系统,而不是添加到请求处理程序的 HTTP 回调。
基本规则很简单:网络钩子报告已提交的状态转换。它不会创建过渡、取代分类账或成为权威记录。当事件可能冻结客户访问、触发信用操作或影响发票时,这种区别就很重要。
首先定义交付合同
既定事实:常见 Webhook 规范和大型 Webhook 发布商假定至少一次传送。重试可能会产生重复,独立的交付可能会无序到达。
建议:在公开端点管理之前发布以下合同API:
- 每个业务事件都有一个稳定、不可变的事件 ID。
- 自动重试和手动重播都会保留相同的事件 ID。
- 至少交付一次;不承诺一次性交付。
- 不保证跨端点或事件类型的顺序。
- 成功的响应意味着接收者持久地接受了该事件,不一定所有下游工作都已完成。
- 网络钩子是通知;合作伙伴 API 读取和账本导出仍然具有权威性。
此合同适合 AI API 经销商平台,因为访问控制和财务事件需要及时通知和可靠的恢复路径。
从狭窄的活动目录开始
不要将每次数据库更新都变成公共事件。发布可供合作伙伴执行并精确定义的转换。
| 事件 | 何时发出 | 典型合作伙伴操作 |
|---|---|---|
customer.created | 客户创建提交 | 在转销商中配置客户门户 |
customer.frozen | 将访问状态更改为冻结 | 禁用本地登录或通知支持人员 |
api_key.created | 关键元数据提交 | 刷新客户的密钥清单 |
api_key.revoked | 撤销生效 | 停止向密钥分配工作 |
balance.low | 可用余额向下超过配置的阈值 | 请求充值或警告客户 |
budget.threshold_crossed | 最终支出超出政策阈值 | 应用本地工作流程或审批规则 |
usage.finalized | 使用量从临时改为已完成 | 更新报告或下游结算 |
credit.adjustment_posted | 提交分类帐调整 | 刷新显示的余额 |
阈值事件需要明确的交叉规则。例如,当先前值低于 80% 并且新值等于或高于 80% 时发出,而不是在每个后续使用记录上发出。定义反转是否可以重新设置阈值以及调整是否可以生成新的交叉。
建议:避免将完整的API密钥、提供商凭据、原始提示或详细的滥用证据放入有效负载中。更喜欢资源标识符和最小状态快照。接收者可以使用合作伙伴 API 获取敏感或快速变化的详细信息。
根据已提交状态创建事件
直接从请求处理程序发布会创建两个失败窗口。回调可能会在数据库事务提交之前逃逸,或者事务可能会在发送回调之前进程失败时提交。事务发件箱会关闭两个窗口。
交易发件箱序列
- 开始控制平面或账本交易。
- 应用权威状态更改。
- 将不可变事件插入同一事务中的发件箱表中。
- 提交一次。
- 让发布商工作人员声明已提交的发件箱行。
- 使用活动的合作伙伴范围和订阅过滤器解析符合条件的端点。
- 为每个事件端点对创建一条传送记录。
对 (event_id, endpoint_id) 的唯一约束可防止工作线程重试时出现重复扇出。应使用比较和设置语义或行锁定来更新发件箱发布状态,以便多个工作人员可以安全地协作。
outbox_event(
event_id, partner_id, type, subject_id,
occurred_at, schema_version, payload, correlation_id,
published_at
)
delivery(
delivery_id, event_id, endpoint_id, state,
attempt_count, next_attempt_at, last_status,
last_latency_ms, last_error_category
)
发件箱添加了数据库写入、清理工作和积压监控。当通知具有财务或访问控制后果时,这些成本是合理的。对于一次性产品遥测,尽力回调可能仍然可以接受,但它不应共享合作伙伴 API webhook 系统的可靠性声明。
使用稳定的事件信封
将业务事件身份与交付尝试身份分开。重试时事件保持不变;尝试时间戳和传送记录发生变化。
{
"event_id": "evt_01J...",
"type": "usage.finalized",
"occurred_at": "2026-10-15T14:22:31Z",
"partner_id": "partner_42",
"subject": {
"type": "usage_record",
"id": "usage_9182"
},
"schema_version": "1",
"correlation_id": "op_7fd...",
"data": {
"customer_id": "cus_204",
"currency": "USD",
"final_cost": "1.274800"
}
}
使用十进制字符串或小单位整数表示货币。记录货币、精度和舍入政策。关联 ID 应将事件连接到原始合作伙伴 API 操作或分类帐发布,而不会成为事件的身份。
强制实施租户安全扇出
在构建特定于端点的负载之前,先解决事件合作伙伴范围内的订阅问题。作业或队列消息提供的端点 ID 不足以授权传送。工作线程应使用相当于 endpoint.partner_id = event.partner_id 的谓词加载端点,并验证它是否处于活动状态并订阅了事件类型。
这是合作伙伴API自动化中租户授权的出站对应项:必须在每个异步边界重新建立对象所有权。
对您发送的确切字节进行签名
既定事实:标准 Webhooks 规范定义了 webhook-id、webhook-timestamp 和 webhook-signature 标头,并一起对事件 ID、尝试时间戳和原始请求正文进行签名。
为每个端点分配一个不同的签名密钥。在最终 JSON 序列化后计算签名,并发送这些确切的字节。签名后重新序列化对象可能会更改空格、转义或属性顺序并使验证无效。
接收方应拒绝超出记录容差的时间戳,计算原始正文的预期 HMAC,并在恒定时间内比较签名。然后,他们应该在确认事件 ID 之前将其保留在唯一约束下。
对于轮换,请暂时允许两个活动密钥并包含两者的签名。仅在合作伙伴确认新秘密后或在记录的重叠期后结束轮换。初始创建后切勿再次暴露现有机密。
让每次交付都可观察且可重播
保留每次尝试的开始时间、状态代码、延迟时间、错误类别、下次重试时间和大小有限的响应摘录。在显示之前编辑标头和响应正文。运营商需要区分 DNS 故障、连接拒绝、TLS 故障、超时、HTTP 拒绝和内部工作器故障。
实用的响应政策是:
200-299:标记已送达。410:停止传送并禁用端点。408、425、429和500-599:重试,遵守配置限制内的有效Retry-After值。- 其他
400-499:分类为持续接收器错误,并仅根据已发布的策略重试。 - 网络和超时故障:使用指数退避和抖动重试。
每个端点的并发上限,以便一个失败的接收器无法使用工作池。在多天内进行重试,通过单独的渠道警告端点所有者,并在记录的故障窗口后禁用端点。
手动重播应该为原始事件端点对创建新的尝试。它不得创建新的业务事件、更改 event_id 或暗示基础操作再次发生。
将回调网址视为 SSRF 边界
合作伙伴控制的回调网址会指示您的基础架构在何处发出网络请求。这使得网络钩子发布者成为 SSRF 目标。
建议: 要求 HTTPS、限制端口、拒绝嵌入凭据并阻止环回、私有、链路本地、多播、保留和云元数据目标。在验证期间解析主机名,并在连接时再次解析主机名。验证每个已解析的地址,而不仅仅是第一个地址。
不要自动遵循重定向。如果支持重定向,请验证每个目标跃点并应用较小的跃点限制。仅连接到经过验证的公共地址,同时保留用于 TLS 验证的预期主机名,从而防止 DNS 重新绑定。
在隔离的网段中运行交付工作人员,无需访问控制平面数据库、内部管理服务、编排 API 或实例元数据。应用请求正文限制、响应大小限制、连接超时和总请求期限。
为重复事件和陈旧事件设计使用者
接收方应验证签名、验证时间戳和架构、将事件 ID 插入持久收件箱、排队处理并快速返回。唯一的事件 ID 约束将并发重复转化为正常的数据库结果。
业务效果需要自己的幂等性控制。如果 credit.adjustment_posted 触发会计导入,则将该导入关键到源调整 ID,而不是假设 Webhook 重复数据删除单独保护分类帐。在接收者提交其效果之后、发布者看到响应之前,可能会发生超时。
对于可变状态(例如键状态),请在应用旧事件之前比较资源版本或获取当前状态。这对于 AI API 预算控制尤其重要,其中延迟的阈值通知不得覆盖较新的限制或执行决策。
版本架构并提供协调
版本网络钩子架构独立于普通合作伙伴API响应。保持附加字段向后兼容,发布 JSON 架构和示例,并为不兼容的语义保留新的事件类型或架构 URI。将每个端点固定到显式事件架构行为,而不是在 API 发生变化时默默地更改负载。
Webhook 还需要基于拉取的恢复:
- 列出光标后的事件,范围仅限于经过身份验证的合作伙伴。
- 检索当前客户、密钥、余额和预算状态。
- 导出某个时间范围内的最终使用情况和分类帐调整。
- 公开传送保留和重播窗口限制。
预测: 合作伙伴最终将因保留过期、端点禁用、部署错误或长时间中断而错过通知。基于游标的事件源和权威状态 API 将该事件转化为协调工作,而不是手动数据修复。
实施清单
- 记录事件语义、交叉规则和数据敏感性。
- 在一笔事务中写入事件和权威更改。
- 在扇出和交付期间强制执行合作伙伴所有权。
- 对稳定事件 ID、尝试时间戳和原始负载字节进行签名。
- 存储每次尝试的证据并公开可搜索的传送历史记录。
- 支持重叠机密、测试事件、禁用和重播。
- 在注册和连接时验证目的地。
- 测试重复项、乱序传送、持久接收后超时、轮换重叠、DNS 重新绑定、专用 IP 重定向、速率限制和延长停机时间。
- 监控发件箱期限、队列深度、成功率、端点禁用和重试饱和度。
- 在递送记录过期后保持调节 API 可用。
围绕权威记录构建通知
可靠的设计并不是更激进的重试循环。它是一个持久边界链:提交状态、事务事件创建、租户范围扇出、签名交付、幂等接收和基于拉动的协调。在扩展事件目录之前实施这些边界。然后,合作伙伴可以自动执行配置、访问控制、余额、预算和使用,而无需将不可靠的 HTTP 交换视为记录系统。