跳转到主要内容

概述

Webhook 是 Qoder Cloud Agents 提供的事件驱动推送机制。当 Agent、Session 等资源发生生命周期变化时,系统以 HTTP POST 方式将结构化事件推送到开发者注册的 URL,无需轮询即可实时获取状态变更。 核心特性:
  • 事件驱动推送 — 资源状态变更时主动通知,无需客户端轮询
  • 信封结构 — 统一的 BetaWebhookEvent { id, created_at, data, type:"event" } 格式
  • 投递语义 — at-least-once 保证;HMAC-SHA256 签名验证;指数退避重试
  • 通配符订阅 — 使用 * 订阅所有事件类型,简化集成配置
适用场景:
场景说明
异步任务完成通知Session 执行完毕后触发下游流程
Agent 配置变更审计记录 Agent 创建/更新/删除操作
多 Agent 协作编排Thread 状态变更驱动子任务调度
运维监控告警连续失败计数超阈值时告警

Domain Types

本节定义 Webhook 事件的数据结构。每种事件类型的 data 字段遵循统一的 object 格式,包含资源 ID、事件类型及事件特定的额外字段。

Session 生命周期事件


Webhook Session Created Event Data

  • WebhookSessionCreatedEventData object { id, type }
    • id: string 触发事件的 Session ID。
    • type: "session.created"
      • "session.created"
      Session 被成功创建时触发。通过 POST /sessions 接口创建 Session 后,系统立即发送此事件。

Webhook Session Updated Event Data

  • WebhookSessionUpdatedEventData object { id, type }
    • id: string 触发事件的 Session ID。
    • type: "session.updated"
      • "session.updated"
      Session 元数据(如 title、metadata 等)被修改时触发。

Webhook Session Archived Event Data

  • WebhookSessionArchivedEventData object { id, type }
    • id: string 触发事件的 Session ID。
    • type: "session.archived"
      • "session.archived"
      Session 被归档时触发。归档后 Session 不再接受新消息,但历史数据仍可查询。

Webhook Session Deleted Event Data

  • WebhookSessionDeletedEventData object { id, type }
    • id: string 触发事件的 Session ID。
    • type: "session.deleted"
      • "session.deleted"
      Session 被永久删除时触发。删除后该 Session 的所有数据将不可恢复。

Session 状态事件


Webhook Session Status Run Started Event Data

  • WebhookSessionStatusRunStartedEventData object { id, type }
    • id: string 触发事件的 Session ID。
    • type: "session.status_run_started"
      • "session.status_run_started"
      Agent 开始一轮运行时触发。标志着 Session 进入 running 状态,正在执行用户指令。

Webhook Session Status Idled Event Data

  • WebhookSessionStatusIdledEventData object { id, type }
    • id: string 触发事件的 Session ID。
    • type: "session.status_idled"
      • "session.status_idled"
      一轮 turn 执行完成,Session 回到 idle 状态时触发。此时可安全地读取 Session 的最新输出。

Session Thread 事件

适用于多 Agent 协作场景。Thread 事件在 Session 事件基础上额外携带 session_thread_id 字段,标识具体的执行线程。

Webhook Session Thread Created Event Data

  • WebhookSessionThreadCreatedEventData object { id, type, session_thread_id }
    • id: string 触发事件的 Session ID。
    • type: "session.thread_created"
      • "session.thread_created"
      新的 Session Thread 被创建时触发。常见于子 Agent 协作场景中,主 Agent 派生子线程执行任务。
    • session_thread_id: string 所属的 Session Thread ID。

Webhook Session Thread Idled Event Data

  • WebhookSessionThreadIdledEventData object { id, type, session_thread_id }
    • id: string 触发事件的 Session ID。
    • type: "session.thread_idled"
      • "session.thread_idled"
      Session Thread 一轮执行结束进入 idle 状态时触发。表示该线程已完成当前任务,可读取结果。
    • session_thread_id: string 所属的 Session Thread ID。

Webhook Session Thread Terminated Event Data

  • WebhookSessionThreadTerminatedEventData object { id, type, session_thread_id }
    • id: string 触发事件的 Session ID。
    • type: "session.thread_terminated"
      • "session.thread_terminated"
      Session Thread 被终止时触发。Thread 终止后不可恢复,需创建新 Thread 继续工作。
    • session_thread_id: string 所属的 Session Thread ID。

Agent 生命周期事件

Agent 事件在基础字段之外额外携带 version 字段,标识 Agent 的配置版本号。

Webhook Agent Created Event Data

  • WebhookAgentCreatedEventData object { id, type, version }
    • id: string 触发事件的 Agent ID。
    • type: "agent.created"
      • "agent.created"
      Agent 被成功创建时触发。通过 POST /agents 接口创建 Agent 后,系统发送此事件。
    • version: integer Agent 版本号。首次创建时为 1

Webhook Agent Updated Event Data

  • WebhookAgentUpdatedEventData object { id, type, version }
    • id: string 触发事件的 Agent ID。
    • type: "agent.updated"
      • "agent.updated"
      Agent 配置被更新时触发。每次更新 version 递增。
    • version: integer Agent 版本号。

Webhook Agent Archived Event Data

  • WebhookAgentArchivedEventData object { id, type, version }
    • id: string 触发事件的 Agent ID。
    • type: "agent.archived"
      • "agent.archived"
      Agent 被归档时触发。归档后 Agent 不再接受新的 Session 创建请求。
    • version: integer Agent 版本号。

Webhook Agent Deleted Event Data

  • WebhookAgentDeletedEventData object { id, type, version }
    • id: string 触发事件的 Agent ID。
    • type: "agent.deleted"
      • "agent.deleted"
      Agent 被删除时触发。删除后该 Agent 的所有配置数据将不可恢复。
    • version: integer Agent 版本号。

Webhook Endpoint API

管理 Webhook 端点的 CRUD 接口。通过这些接口可以创建、查询、更新、删除 Webhook 端点,以及发送测试事件和控制端点的启用/禁用状态。 Base URL:
区域地址
Globalhttps://api.qoder.com/api/v1/cloud
CNhttps://api.qoder.com.cn/api/v1/cloud
认证方式: 所有接口均需要在请求头中携带 Personal Access Token:
Authorization: Bearer $PAT

POST /webhook_endpoints

创建一个新的 Webhook 端点。 请求参数:
字段类型必填说明
urlstring接收事件推送的 HTTP 或 HTTPS URL(生产环境强烈建议使用 HTTPS)
descriptionstring端点描述,便于管理识别
eventsstring[]订阅的事件类型列表,支持 * 通配符
响应: 201 Created
{
  "id": "5fc05310-4d9c-447e-a4b8-f124f17e1ff0",
  "url": "https://webhook.site/your-unique-path",
  "description": "quickstart demo",
  "events": ["*"],
  "active": true,
  "signing_secret": "whsec_BfJDodFEzmkdjAUf19-_XthSq6KbPKmRjfm9KFWMIuk",
  "signing_secret_version": 1,
  "created_at": "2026-07-02T18:17:30.069191+08:00"
}
注意: signing_secret 仅在创建时返回一次,请妥善保存。后续查询接口不会再次返回此字段。
状态码:
状态码说明
201创建成功
400请求参数无效(如 URL 格式错误、事件类型不合法)
401未授权,Token 无效或过期
422语义错误(如 URL 重复注册)
示例:
curl -X POST https://api.qoder.com/api/v1/cloud/webhook_endpoints \
  -H "Authorization: Bearer $PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://webhook.site/your-unique-path",
    "description": "quickstart demo",
    "events": ["*"]
  }'

GET /webhook_endpoints

获取当前账户下所有 Webhook 端点列表。 请求参数: 响应: 200 OK
{
  "data": [
    {
      "id": "700e7789-edab-41cb-b60a-210d0df38ab6",
      "url": "https://myapp.example.com/hooks/qoder",
      "description": "prod app hook",
      "events": ["session.created", "session.thread_idled"],
      "active": true,
      "signing_secret_version": 1,
      "consecutive_fail": 0,
      "last_success_at": "2026-07-02T18:08:12.666783+08:00",
      "created_at": "2026-07-02T17:47:16.073822+08:00",
      "updated_at": "2026-07-02T17:47:16.073822+08:00"
    }
  ]
}
响应字段说明:
字段类型说明
idstring端点唯一标识
urlstring接收事件的 URL
descriptionstring端点描述
eventsstring[]订阅的事件类型列表
activeboolean是否启用
signing_secret_versioninteger签名密钥版本号
consecutive_failinteger连续投递失败次数
last_success_atstring最近一次成功投递时间(RFC 3339)
last_failure_atstring最近一次投递失败时间(RFC 3339),无失败记录时为 null
created_atstring创建时间(RFC 3339)
updated_atstring最近更新时间(RFC 3339)
示例:
curl https://api.qoder.com/api/v1/cloud/webhook_endpoints \
  -H "Authorization: Bearer $PAT"

GET /webhook_endpoints/{id}

获取指定 Webhook 端点的详细信息。 路径参数:
参数类型说明
idstringWebhook 端点 ID
响应: 200 OK 返回单个端点对象,结构与列表接口中的元素一致。 状态码:
状态码说明
200成功
404端点不存在
示例:
curl https://api.qoder.com/api/v1/cloud/webhook_endpoints/700e7789-edab-41cb-b60a-210d0df38ab6 \
  -H "Authorization: Bearer $PAT"

PUT /webhook_endpoints/{id}

更新指定 Webhook 端点的配置。 路径参数:
参数类型说明
idstringWebhook 端点 ID
请求参数:
字段类型必填说明
urlstring更新接收事件推送的 URL
descriptionstring更新端点描述
eventsstring[]更新订阅的事件类型列表
响应: 200 OK 返回更新后的完整端点对象。 状态码:
状态码说明
200更新成功
400请求参数无效
404端点不存在
示例:
curl -X PUT https://api.qoder.com/api/v1/cloud/webhook_endpoints/700e7789-edab-41cb-b60a-210d0df38ab6 \
  -H "Authorization: Bearer $PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["session.created", "session.status_idled", "agent.updated"],
    "description": "updated prod hook"
  }'

DELETE /webhook_endpoints/{id}

永久删除指定的 Webhook 端点。删除后所有未投递的事件将被丢弃。 路径参数:
参数类型说明
idstringWebhook 端点 ID
响应: 204 No Content 状态码:
状态码说明
204删除成功
404端点不存在
示例:
curl -X DELETE https://api.qoder.com/api/v1/cloud/webhook_endpoints/700e7789-edab-41cb-b60a-210d0df38ab6 \
  -H "Authorization: Bearer $PAT"

POST /webhook_endpoints/{id}/test

向指定端点发送一个测试事件,用于验证端点连通性和签名验证逻辑。 路径参数:
参数类型说明
idstringWebhook 端点 ID
请求参数: 响应: 202 Accepted
{"event_id": 433, "delivery_rows": 2}
响应字段说明:
字段类型说明
event_idinteger测试事件的内部 ID
delivery_rowsinteger事件发布的消息分区数
状态码:
状态码说明
202测试事件已发送
404端点不存在
示例:
curl -X POST https://api.qoder.com/api/v1/cloud/webhook_endpoints/700e7789-edab-41cb-b60a-210d0df38ab6/test \
  -H "Authorization: Bearer $PAT"

POST /webhook_endpoints/{id}/enable

启用一个被禁用的 Webhook 端点。启用后端点将重新接收事件推送。 路径参数:
参数类型说明
idstringWebhook 端点 ID
请求参数: 响应: 200 OK 返回启用后的端点对象(active: true)。 状态码:
状态码说明
200启用成功
404端点不存在
示例:
curl -X POST https://api.qoder.com/api/v1/cloud/webhook_endpoints/700e7789-edab-41cb-b60a-210d0df38ab6/enable \
  -H "Authorization: Bearer $PAT"

POST /webhook_endpoints/{id}/disable

禁用一个 Webhook 端点。禁用后端点将停止接收事件推送,但不会被删除。 路径参数:
参数类型说明
idstringWebhook 端点 ID
请求参数: 响应: 200 OK 返回禁用后的端点对象(active: false)。 状态码:
状态码说明
200禁用成功
404端点不存在
示例:
curl -X POST https://api.qoder.com/api/v1/cloud/webhook_endpoints/700e7789-edab-41cb-b60a-210d0df38ab6/disable \
  -H "Authorization: Bearer $PAT"

GET /webhook_events

列出 Webhook 事件投递记录,用于审计和排查。 请求参数: 响应: 200 OK 返回事件列表,包含事件的投递状态、时间戳等信息。 示例:
curl https://api.qoder.com/api/v1/cloud/webhook_events \
  -H "Authorization: Bearer $PAT"

GET /webhook_events/{id}

获取单个 Webhook 事件的详细信息。 路径参数:
参数类型说明
idstringWebhook 事件 ID
响应: 200 OK 状态码:
状态码说明
200成功
404事件不存在
示例:
curl https://api.qoder.com/api/v1/cloud/webhook_events/433 \
  -H "Authorization: Bearer $PAT"

错误响应格式

所有接口在遇到错误时,返回统一的错误结构:
{
  "error": {
    "message": "Unknown event type: agent.updated",
    "type": "invalid_request_error"
  },
  "request_id": "cc865161-b25d-4d68-bad5-bf0363f6e0f9",
  "type": "error"
}
错误字段说明:
字段类型说明
error.messagestring人类可读的错误描述
error.typestring错误分类(如 invalid_request_errornot_found_error
request_idstring请求追踪 ID,用于排查问题时提供给支持团队
typestring固定值 "error"
注意: 鉴权层(如 Token 无效或缺失)返回的 401 响应可能不遵循上述业务错误结构,而是由网关直接返回。

Webhook Delivery(投递机制)

投递方式

系统通过 HTTP POST 将事件推送到注册的 URL,请求格式如下:
  • Method: POST
  • Content-Type: application/json
  • Body: JSON 格式的信封结构(详见信封结构详解

请求头

每次投递包含以下 HTTP 请求头:
Header说明
Content-Typeapplication/json
User-AgentQoderCloudAgents-Webhook/1.0
Webhook-SignatureHMAC-SHA256 签名,格式为 t=<unix_epoch>,v1=<hmac_sha256_hex>

签名验证

为确保事件来源的真实性和数据完整性,每次投递都携带 HMAC-SHA256 签名。开发者应在接收端验证签名后再处理事件。 签名格式:
t=1719907336,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8f9
签名算法:
signature = HMAC_SHA256(signing_secret, "<t>.<raw_body>")
其中:
  • signing_secret — 创建端点时返回的密钥(whsec_ 前缀)
  • t — 签名时的 Unix 时间戳(秒)
  • raw_body — 请求体的原始字节内容(未经解析)
验证步骤:
  1. Webhook-Signature Header 中提取 tv1
  2. 检查时间戳是否在容忍窗口内(建议 600 秒),防止重放攻击
  3. 使用 signing_secret"<t>.<raw_body>" 计算 HMAC-SHA256
  4. 将计算结果与 v1 进行恒时比较(timing-safe comparison)

签名验证代码示例

Node.js:
const crypto = require('node:crypto');

function verifyWebhook(secret, rawBody, header, toleranceSec = 600) {
  const parts = Object.fromEntries(
    header.split(',').map(kv => kv.split('=').map(s => s.trim()))
  );
  const ts = parseInt(parts.t, 10);
  if (Math.abs(Date.now() / 1000 - ts) > toleranceSec) return false;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${ts}.${rawBody}`)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(parts.v1, 'hex')
  );
}
Python:
import hmac, hashlib, time

def verify_webhook(secret: bytes, raw_body: bytes, header: str, tolerance_sec: int = 600) -> bool:
    parts = dict(kv.split("=", 1) for kv in header.split(","))
    ts = int(parts["t"])
    if abs(time.time() - ts) > tolerance_sec:
        return False
    signed_payload = f"{ts}.".encode() + raw_body
    expected = hmac.new(secret, signed_payload, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"])
Go:
func verifyWebhook(secret, rawBody []byte, header string, toleranceSec int64) bool {
    var ts int64; var v1 string
    for _, kv := range strings.Split(header, ",") {
        kv = strings.TrimSpace(kv)
        if strings.HasPrefix(kv, "t=") { ts, _ = strconv.ParseInt(kv[2:], 10, 64) }
        if strings.HasPrefix(kv, "v1=") { v1 = kv[3:] }
    }
    if ts == 0 || v1 == "" { return false }
    if diff := time.Now().Unix() - ts; diff > toleranceSec || diff < -toleranceSec { return false }
    mac := hmac.New(sha256.New, secret)
    fmt.Fprintf(mac, "%d.", ts)
    mac.Write(rawBody)
    return hmac.Equal([]byte(hex.EncodeToString(mac.Sum(nil))), []byte(v1))
}

重试策略

当投递失败时,系统采用指数退避策略进行重试:
尝试次数延迟说明
第 1 次立即首次投递
第 2 次1 秒第一次重试
第 3 次5 秒第二次重试
第 4 次30 秒最终重试
共计 4 次尝试(1 次投递 + 3 次重试)。全部失败后事件进入死信队列。

响应码处理

响应码范围处理方式
2xx投递成功,事件标记为已送达
4xx不重试,事件标记为已丢弃(客户端错误应由开发者修复)
5xx触发重试(服务端临时故障)
超时触发重试(默认超时 30 秒)

自动降级

当某个端点的 consecutive_fail 计数超过 20 时,系统将触发降级警告。建议开发者监控此指标,并在持续失败时检查:
  • 端点 URL 是否可达
  • SSL 证书是否有效
  • 服务端是否正常响应
  • 签名验证逻辑是否存在 Bug

Supported Event Types(完整清单)

事件类型总览

事件类型状态data 额外字段触发条件
session.created✅ 已实现POST /sessions 成功创建 Session
session.updated✅ 已实现Session 元数据被修改
session.archived✅ 已实现Session 被归档
session.deleted✅ 已实现Session 被永久删除
session.status_run_started✅ 已实现Agent 开始一轮运行
session.status_idled✅ 已实现Turn 执行完成,回到 idle 状态
session.thread_created✅ 已实现session_thread_id新的 Session Thread 被创建
session.thread_idled✅ 已实现session_thread_idThread 执行结束进入 idle
session.thread_terminated✅ 已实现session_thread_idThread 被终止
agent.created✅ 已实现versionPOST /agents 创建 Agent
agent.updated✅ 已实现versionAgent 配置被更新
agent.archived✅ 已实现versionAgent 被归档
agent.deleted✅ 已实现versionAgent 被删除
session.pending🔜 白名单已注册Session 等待调度
session.running🔜 白名单已注册Session 正在运行
session.idled🔜 白名单已注册Session 进入 idle
session.requires_action🔜 白名单已注册Session 需要人工介入
session.status_run_failed🔜 白名单已注册运行失败
session.status_terminated🔜 白名单已注册Session 被终止
session.status_rescheduled🔜 白名单已注册Session 被重新调度
session.status_paused_pending_input🔜 白名单已注册暂停等待用户输入
session.status_paused_pending_approval🔜 白名单已注册暂停等待审批
session.status_paused_user_intervention🔜 白名单已注册暂停等待人工干预
session.outcome_evaluation_started🔜 白名单已注册结果评估开始
session.outcome_evaluation_ended🔜 白名单已注册结果评估结束
vault.created🔜 白名单已注册密钥库创建
vault.deleted🔜 白名单已注册密钥库删除
vault.updated🔜 白名单已注册密钥库更新
vault_credential.created🔜 白名单已注册凭据创建
vault_credential.updated🔜 白名单已注册凭据更新
vault_credential.deleted🔜 白名单已注册凭据删除
vault_credential.shared🔜 白名单已注册凭据共享
vault_credential.revoked🔜 白名单已注册凭据撤销
deployment.created📋 规划中部署创建
deployment.updated📋 规划中部署更新
deployment.archived📋 规划中部署归档
deployment.deleted📋 规划中部署删除
deployment.paused📋 规划中部署暂停
deployment.unpaused📋 规划中部署恢复
deployment_run.started📋 规划中部署运行开始
deployment_run.failed📋 规划中部署运行失败
deployment_run.succeeded📋 规划中部署运行成功
environment.created📋 规划中环境创建
environment.updated📋 规划中环境更新
environment.archived📋 规划中环境归档
environment.deleted📋 规划中环境删除
memory_store.created📋 规划中记忆存储创建
memory_store.archived📋 规划中记忆存储归档
memory_store.deleted📋 规划中记忆存储删除

特殊事件类型

事件类型说明
*通配符,订阅所有事件类型。在创建端点时使用 ["*"] 可接收全部事件推送
webhook.test内部测试事件,通过 POST /webhook_endpoints/{id}/test 触发

状态标记说明

标记含义
✅ 已实现系统中存在完整的事件触发点,可正常订阅和接收
🔜 白名单已注册事件类型已在验证白名单中注册(可用于 events 字段),但暂无触发点
📋 规划中事件类型已在 API 设计层面完成定义,尚未注册到白名单

信封结构详解

所有 Webhook 事件均使用统一的信封(envelope)结构进行封装投递。

基础信封结构

{
  "id": "whevt_a1b2c3d4e5f67890",
  "created_at": "2026-07-02T10:02:16Z",
  "type": "event",
  "data": {
    "id": "sess_019f224773fe71d79c5869bd089d159c",
    "type": "session.created"
  }
}

Thread 事件信封

Thread 事件的 data 中额外包含 session_thread_id 字段:
{
  "id": "whevt_a1b2c3d4e5f67890",
  "created_at": "2026-07-02T10:02:17Z",
  "type": "event",
  "data": {
    "id": "sess_019f224773fe71d79c5869bd089d159c",
    "type": "session.thread_idled",
    "session_thread_id": "sthread_019f224..."
  }
}

Agent 事件信封

Agent 事件的 data 中额外包含 version 字段:
{
  "id": "whevt_a1b2c3d4e5f67890",
  "created_at": "2026-07-02T10:02:16Z",
  "type": "event",
  "data": {
    "id": "agent_019f224773fe71d7...",
    "type": "agent.created",
    "version": 1
  }
}

字段说明

字段类型说明
idstring事件唯一标识。格式为 whevt_ + 唯一标识符,由事件的 idempotency key 确定性生成
created_atstring事件创建时间,RFC 3339 UTC 格式
typestring固定值 "event",标识这是一个事件信封
dataobject事件负载,包含触发资源的信息
data.idstring触发事件的资源 ID(Session ID 或 Agent ID)
data.typestring事件类型字符串,如 "session.created""agent.updated"
data.session_thread_idstring(仅 Thread 事件)所属的 Session Thread ID
data.versioninteger(仅 Agent 事件)Agent 配置版本号

幂等性处理

信封中的 id 字段可作为去重键(deduplication key)。由于投递语义为 at-least-once,同一事件可能被多次推送。接收端应:
  1. 使用 id 作为唯一键进行去重
  2. 在处理前检查该 id 是否已被消费
  3. 确保事件处理逻辑的幂等性

规划中的事件(Coming Soon)

以下事件类型已在 API 设计层面完成对齐,将随各资源功能上线后逐步开放。具体时间线视产品需求确定。

deployment.* (部署生命周期,6 个事件)

事件类型触发条件
deployment.created新部署被创建
deployment.updated部署配置被更新
deployment.archived部署被归档
deployment.deleted部署被删除
deployment.paused部署被暂停(停止触发新运行)
deployment.unpaused部署被恢复(重新开始触发运行)

deployment_run.* (部署运行状态,3 个事件)

事件类型触发条件
deployment_run.started一次部署运行开始执行
deployment_run.failed部署运行失败
deployment_run.succeeded部署运行成功完成

environment.* (环境管理,4 个事件)

事件类型触发条件
environment.created运行环境被创建
environment.updated环境配置被更新
environment.archived环境被归档
environment.deleted环境被删除

memory_store.* (记忆存储,3 个事件)

事件类型触发条件
memory_store.created记忆存储实例被创建
memory_store.archived记忆存储被归档
memory_store.deleted记忆存储被删除

vault.* (密钥库,3 个事件)

事件类型触发条件
vault.created密钥库被创建
vault.updated密钥库配置被更新
vault.deleted密钥库被删除

vault_credential.* (凭据管理,5 个事件)

事件类型触发条件
vault_credential.created新凭据被添加到密钥库
vault_credential.updated凭据信息被更新
vault_credential.deleted凭据被删除
vault_credential.shared凭据被共享给其他 Agent
vault_credential.revoked凭据的共享权限被撤销

附录 A:快速接入指南

步骤 1:创建 Webhook 端点

curl -X POST https://api.qoder.com/api/v1/cloud/webhook_endpoints \
  -H "Authorization: Bearer $PAT" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.example.com/webhooks/qoder",
    "description": "Production webhook",
    "events": ["session.status_idled", "session.thread_idled"]
  }'

步骤 2:保存 signing_secret

从创建响应中获取 signing_secret 并安全存储,后续验证签名时使用。

步骤 3:实现接收端

在您的服务中实现 Webhook 接收端点,确保:
  1. 验证 Webhook-Signature 签名
  2. 使用事件 id 做幂等去重
  3. 返回 200 OK 确认收到
  4. 异步处理业务逻辑(避免超时)

步骤 4:发送测试事件

curl -X POST https://api.qoder.com/api/v1/cloud/webhook_endpoints/{id}/test \
  -H "Authorization: Bearer $PAT"

步骤 5:验证并上线

确认测试事件接收正常后,即可投入生产使用。

附录 B:最佳实践

实践说明
签名验证始终验证 Webhook-Signature,拒绝无效请求
幂等处理使用事件 id 去重,防止重复消费
快速响应接收端应在 5 秒内返回 2xx,耗时逻辑异步处理
时间戳校验拒绝超过容忍窗口的事件,防止重放攻击
精确订阅仅订阅需要的事件类型,减少不必要的网络开销
监控告警监控 consecutive_fail 指标,及时发现投递异常