外观
Webhook 模式篇
目标:让集成方创建事件订阅、看懂推送请求的 payload 信封与请求头、按事件类型路由处理、用幂等键去重、理解平台的自动重试与失败排障,端到端接住内容变更回调。
不在本篇范围:订阅各端点的逐字段参数(见接口参考);资源详情字段(payload 只给资源引用,详情凭 ID 回调对应资源端点取,见领域模型);错误码完整码表(见错误码参考)。
Webhook 让 ATKONBASE 在内容发生变更时主动回调你的接收端点,免去你轮询查询。你创建一个订阅、声明关心的事件类型与接收 URL;之后对应业务操作提交后,平台异步向该 URL POST 一条轻量引用信封,你据此回调相应资源端点取详情。
关键事实
- 推送在业务操作提交后异步发出(通常数十秒内送达),不与触发操作同步、不保证即时。
- 推送请求体是轻量引用信封——只含事件元信息 + 资源类型/ID,不含资源完整内容;你凭
resource.id回调对应资源端点取详情。 - 投递为至少一次(at-least-once):失败会重试,同一事件可能被推送多次;用幂等键
eventId去重。 - 同一订阅的多个事件不保证到达顺序,按 best-effort 投递。
- ⚠️ 当前版本推送不带 payload 签名,请求体为明文 JSON。来源校验首选在订阅上配置出站投递授权 token(
deliveryToken)、核对推送携带的Authorization: Bearer头;并辅以接收端点走 HTTPS、URL 保持不可猜测 / 不公开、以eventId幂等处理(见下文来源校验与安全)。 - 只有
ACTIVE状态的订阅会产生并接收推送;PAUSED/DISABLED不推送。
一、创建订阅
bash
curl -X POST 'https://api.atkonbase.example.com/v1/webhooks/save' \
-H 'Authorization: Bearer ${accessToken}' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://your-app.example.com/atk/webhook",
"eventTypes": "document.created,document.updated",
"description": "文档变更通知",
"deliveryToken": "a-long-random-shared-secret"
}'| 字段 | 说明 |
|---|---|
url | 接收推送的目标 URL,须可公网访问、建议 HTTPS |
eventTypes | 订阅的事件类型,逗号分隔;* 表示订阅全部 |
description | 描述(可选) |
deliveryToken | 出站投递授权 token(可选,只写):配置后平台投递本订阅的事件时以 Authorization: Bearer <token> 携带,供你校验推送来源(见来源校验与安全)。不在 get / 列表 / 保存响应中回显;保存时显式传值即覆盖、传空字符串即清除、不传则保持原值 |
- 创建后订阅状态固定为
ACTIVE,立即生效。 - 改状态走
updateStatus、删除走delete(见下);完整参数见接口参考 · 创建订阅。
其它订阅管理端点
bash
# 分页查订阅
curl -X GET 'https://api.atkonbase.example.com/v1/webhooks/getPage?page=1&pageSize=20' \
-H 'Authorization: Bearer ${accessToken}'
# 查订阅详情
curl -X GET 'https://api.atkonbase.example.com/v1/webhooks/get?webhookId=${webhookId}' \
-H 'Authorization: Bearer ${accessToken}'
# 改状态(ACTIVE / PAUSED / DISABLED)
curl -X GET 'https://api.atkonbase.example.com/v1/webhooks/updateStatus?webhookId=${webhookId}&status=PAUSED' \
-H 'Authorization: Bearer ${accessToken}'
# 删订阅
curl -X GET 'https://api.atkonbase.example.com/v1/webhooks/delete?webhookId=${webhookId}' \
-H 'Authorization: Bearer ${accessToken}'
# 查可订阅事件类型清单
curl -X GET 'https://api.atkonbase.example.com/v1/webhooks/event-types' \
-H 'Authorization: Bearer ${accessToken}'PAUSED期间不推送、也不积压补投;恢复ACTIVE后仅对其后发生的事件推送。
二、可订阅事件类型
event-types 返回以下 8 类事件,均已接真实发布点——订阅后对应业务操作提交即会产生推送:
| 事件类型 | 触发时机 |
|---|---|
document.created | 文档创建 |
document.updated | 文档更新(元数据 / 内容 / 属性更新均归并到此) |
document.deleted | 文档删除(移入回收站) |
document.archived | 文档归档(独立于更新,归档只触发本事件、不再触发 document.updated) |
container.created | 容器创建 |
container.updated | 容器更新 |
container.deleted | 容器删除(移入回收站) |
acl.changed | 权限变更(授权、撤销、策略调整) |
- 删除语义为「移入回收站」(trash):
document.deleted/container.deleted在资源被移入回收站时触发;彻底清除(purge)不对外推送为 webhook 事件。 document.updated归并多种更新来源(元数据 / 内容 / 属性),你收到后凭resource.id回调取最新状态即可,无需区分更新子类。
三、推送请求结构
平台向你的 url 发起一个 POST,Content-Type: application/json。
请求头
| 请求头 | 含义 |
|---|---|
X-Webhook-Event-Id | 事件唯一 ID,即幂等键,与请求体 eventId 一致 |
X-Webhook-Event-Type | 事件类型(如 document.created),便于路由分发 |
X-Webhook-Id | 触发本次推送的订阅 ID |
请求体(轻量引用信封)
json
{
"eventId": "9f1c2e7a-5b3d-4e8a-9c10-2b6f4d8e1a3c",
"eventType": "document.created",
"occurredAt": "2026-05-25T07:00:00Z",
"resource": {
"type": "document",
"id": "D1000001"
}
}| 字段 | 含义 |
|---|---|
eventId | 事件唯一 ID,幂等去重键;同一事件的重复推送携带相同值 |
eventType | 事件类型,取值同上表 8 类 |
occurredAt | 事件发生时间,ISO-8601 UTC(如 2026-05-25T07:00:00Z) |
resource.type | 资源类型,如 document / container |
resource.id | 资源业务 ID,凭此回调对应资源端点取完整详情 |
- 信封不内嵌资源快照:避免推送内容与资源当前状态不一致、避免敏感字段随推送外泄。需要详情时用
resource.id回调对应资源端点(如文档详情)。 - 你的接收端点应在成功处理后返回 2xx;非 2xx 会被判为失败并进入重试。
四、确认接收与重试
平台按下游响应判定单次投递结果:
| 下游响应 | 判定 | 后续 |
|---|---|---|
| 2xx | 成功 | 该投递终态 SUCCESS,不再推送 |
| 非 2xx | 失败 | 进入重试,直至达上限 |
| 超时 / 连接失败 | 失败 | 进入重试,直至达上限 |
重试为指数退避。默认最多尝试 5 次(含首次投递)——即首投失败后,依次在 +30 秒、+2 分钟、+10 分钟、+1 小时 各重试一次;4 次重试仍失败,则该投递置为终态 FAILED、不再推送。
首投 ──(失败)──> +30秒 ──> +2分钟 ──> +10分钟 ──> +1小时 ──(仍失败)──> FAILED- 退避档位按
30 秒 → 2 分钟 → 10 分钟 → 1 小时阶梯递增;默认策略最多重试到 +1 小时档;退避节奏可能随版本调整。 - 上述为平台默认重试策略,由平台统一调度、不可在订阅上配置,可能随版本调整。
- ⚠️ 因为重试存在,同一事件可能被多次推送——你的接收端点必须幂等:用
eventId(=X-Webhook-Event-Id)记录「已处理事件」,重复到达时直接确认 2xx、不重复执行业务。
五、来源校验与安全
当前版本推送为明文 JSON、不带 payload 签名头。在你的接收端点上建议:
- 校验投递授权 token(首选):创建 / 更新订阅时配置一个足够随机的
deliveryToken;平台投递本订阅的事件时会以Authorization: Bearer <token>携带该值,你的接收端点逐请求比对该头是否等于你配置的 token,不匹配即拒绝。该 token 为只写凭据、不在任何读路径回显,请妥善保存。 - 限定接收 URL 不公开:使用足够随机、不可猜测的路径,不对外宣传该 URL。
- 走 HTTPS:接收端点使用 HTTPS,避免明文传输被中间人窜改、以及
deliveryToken在传输中泄露。 - 幂等处理:以
eventId去重(见上),重复推送不产生副作用。 - 凭 ID 回查权威状态:信封只给资源引用;以你的访问凭证回调资源端点取详情,即等于用一次已鉴权的查询确认事件所述资源的真实当前状态,不把信封内容当作终值。
deliveryToken是一个共享密钥式的承载凭据(校验「推送是否来自本平台」);基于密钥对每条 payload 做请求签名(防篡改)的能力仍在后续版本规划中。在其提供前,按上述方式承载来源校验。
六、投递记录与手动重投
每次投递都会落一条可查询的记录,用于排障:
bash
# 查某订阅的投递记录
curl -X GET 'https://api.atkonbase.example.com/v1/webhooks/getDeliveries?webhookId=${webhookId}&page=1&pageSize=20' \
-H 'Authorization: Bearer ${accessToken}'投递记录关键字段:
| 字段 | 含义 |
|---|---|
status | PENDING(待投递)/ RETRYING(重试中)/ SUCCESS(成功)/ FAILED(达上限失败) |
attemptCount | 已尝试次数 |
lastResponseCode | 最近一次下游响应码(超时/连接失败时为空) |
lastResponseBody | 最近一次下游响应体片段(截断保存,便于定位下游报错) |
lastError | 最近一次失败的错误信息 |
nextRetryAt | 下次重试时间(终态时为空) |
手动重投
下游修复后,可对某条投递记录触发重新投递——重置为待投递并清零尝试计数,随后被重新推送:
bash
curl -X POST 'https://api.atkonbase.example.com/v1/webhooks/redeliver?deliveryId=${deliveryId}' \
-H 'Authorization: Bearer ${accessToken}'- 重投携带与原推送相同的
eventId——若该事件此前已被你成功处理,幂等去重应让重投不产生重复副作用。
常见坑
- ⚠️ 接收端点不幂等:未按
eventId去重,重试 / 重投导致同一事件被处理多次。规避:先查eventId是否已处理,已处理直接返回 2xx。 - ⚠️ 把信封当详情用:信封只有资源 ID,不含内容;漏了回调取详情会拿不到业务字段。规避:收到事件后用
resource.id回查资源端点。 - ⚠️ 接收端点慢:处理耗时超过下游读取超时会被判失败并重试。规避:接收端点快速入队后立即返回 2xx,业务处理异步做。
- ⚠️ 误期望顺序:同一订阅多事件不保证到达顺序。规避:以资源当前状态为准(回查),不依赖事件先后。
- ⚠️ 订阅
PAUSED期间的事件不会补投:暂停期间发生的事件不积压、恢复后不补发。规避:需要不漏接时改用DISABLED/ACTIVE切换前评估,或暂停后用查询补齐。 - ⚠️ 删除是「移入回收站」语义:
*.deleted对应 trash,不是彻底清除;彻底清除不推送。规避:按 trash 语义处理删除事件。
下一步
- 收到事件后回调取资源详情 → 领域模型、文件上传链路模式篇
- 订阅 / 投递端点逐字段参数 → 接口参考 · Webhook
- Webhook 调用返回的错误响应 → 错误码参考