Webhook 参考

事半AI 平台向外部系统推送事件的 Webhook 说明——目前包含话单回调。

事半AI 平台通过 Webhook 主动向接入方推送事件。目前支持的事件如下:

事件触发时机说明
话单回调一通电话结束后推送该通通话的话单、意向结果与完整对话记录

话单回调(接入方实现)

通话结束后,系统主动向接入方推送话单(含通话记录、意向结果、对话日志)。

接入方需提供

配置项说明
推送地址(url)接收话单的 HTTPS POST 接口地址
应用 ID(appId)标识接口调用方,也可用于区分业务
应用密钥(appSecret)用于签名验证
加密方法md5sha256

请求 Header

参数名类型必填说明
Content-Typestringapplication/json
X-App-Idstring应用 ID
X-Timestampint64当前时间戳(秒)
X-Noncestring随机字符串(防重放)
X-Signstring签名值
X-Sign-Methodstringmd5sha256

请求 Body

{
  "contextId": "string",        // 三方业务标识——目前恒为空字符串,见下方说明
  "callId": "string",           // 话单唯一标识(以此字段做幂等)
  "phone": "string",            // 被叫手机号
  "caller": "string",           // 线路主叫账号,见下方说明(不一定是电话号码格式)
  "position": "string",         // 数字人岗位名称
  "callMakeTime": 1234567890,   // 呼叫发起时间(秒级时间戳)
  "callRingTime": 1234567890,   // 振铃时间(秒级时间戳)
  "callAnswerTime": 1234567890, // 接通时间(秒级时间戳,未接通则为 0)
  "callHangupTime": 1234567890, // 挂机时间(秒级时间戳)
  "callDuration": 5,            // 通话时长(分钟,向上取整,不满1分钟按1分钟算;精确时长请用 callDurationSeconds)
  "callDurationSeconds": 300,   // 通话时长(秒),精确值
  "recordUrl": "string",        // 通话录音下载地址(有效期 7 天)
  "summary": "string",          // AI 生成的通话摘要
  "intentionStatus": 2,         // 意向状态:0=无结果 1=无意向 2=有意向
  "intentionRank": "string",    // 意向等级(如 A/B/C/D,由话术配置决定)
  "intentionTag": {             // AI 提取的结构化意向标签(由话术配置决定字段)
    "key1": "value1"
  },
  "chatLogs": [                 // 完整对话记录
    {
      "begin": "2024-01-01 12:00:00",  // 本句开始时间,可能为空字符串(见下方说明)
      "end": "2024-01-01 12:00:05",    // 本句结束时间,可能为空字符串(见下方说明)
      "role": "assistant",             // 角色:assistant=AI,user=用户
      "text": "您好,请问有什么可以帮您?"
    }
  ],
  "hangupType": "string",       // 目前恒为 "normal",暂无实际区分意义,不建议依赖
  "answerStatus": 0,            // 目前恒为 0,不能用它判断是否接通,请用 callAnswerTime > 0 判断
  "answerMainStatus": 0,        // 目前恒为 0,同上
  "wechatStatus": 0,            // 目前恒为 0(该字段暂未接入落库),电话场景可忽略
  "wechatSeatName": "string",   // 目前恒为空字符串(微信人工坐席场景使用,电话场景无意义)
  "wechatSeatPhone": "string",  // 目前恒为空字符串,同上
  "sipStatus": "string",        // 目前恒为空字符串,暂无实际内容
  "clueAttr": {},               // 自定义线索字段透传对象,需要在数字人"信息提取"配置里开启白名单才会有值,默认为空对象
  "clueImportLabel": "string"   // 线索导入批次标签,目前暂无法用于区分"平台网页测试拨打"与"正式 API 导入"
}

字段可用性说明hangupTypeanswerStatusanswerMainStatuswechatStatuswechatSeatNamewechatSeatPhonesipStatus 这 7 个字段目前在电话场景下都是固定值/占位值,暂时没有实际业务含义,不建议在这几个字段上写判断逻辑,后续如果补上真实取值会在此更新。clueImportLabel 是真实字段,但目前无法用来区分测试拨打和正式线索;如果收到的话单 phone 不是有效手机号格式(比如一串随机字符)、caller 为空,通常是平台内网页测试拨打产生的数据,可以直接忽略。

contextId 线索关联透传(重要):这个字段目前恒为空字符串,尚未实现,无法用它把话单关联回你推送线索时的标识。在这个能力上线之前,建议按以下优先级关联:① 优先用 phone + callHangupTime(挂断时间)匹配同一时间窗口内你自己推送的线索;② 或者主动调用系统集成文档中的「查询线索通话结果」/「批量查询线索」接口按 phone/programId 反查,拿到权威的 threadDetailId/callId。平台侧正在评估支持线索自定义标识透传,上线后会更新本文档。

caller 说明:这是线路配置的主叫账号(如 250105ltwu),不是用户手机上看到的外显号码,也不一定是标准电话号码格式。如果需要外显号码和 caller 保持一致,可以在申请/配置线路时提出这个要求。

chatLogs[].begin/end 为空:已知在部分对话被打断或应答极短的情况下,这两个时间戳可能返回空字符串,使用前请判空处理。具体触发条件目前还在核实,如果这个问题影响到你的业务逻辑,欢迎带上具体样本反馈给我们。

回调里没有 threadId/threadDetailId:当前话单回调 payload 本身不包含线索 ID,无法直接和线索导入接口返回的线索 ID 对应,这也是上面 contextId 透传问题的一部分,处理方式同上。

签名规则

1. 拼接签名字符串:

timestamp={timestamp}&nonce={nonce}&appId={appId}&data={body_json_string}&appSecret={appSecret}

2. 对拼接后的字符串做哈希,结果即为 X-Sign 的值:

  • X-Sign-Method: md5 → MD5
  • X-Sign-Method: sha256 → SHA256

验签示例(Node.js):

const crypto = require('crypto')

function verifySign(headers, bodyStr, appSecret) {
  const { 'x-timestamp': ts, 'x-nonce': nonce, 'x-app-id': appId,
          'x-sign': sign, 'x-sign-method': method = 'md5' } = headers
  const raw = `timestamp=${ts}&nonce=${nonce}&appId=${appId}&data=${bodyStr}&appSecret=${appSecret}`
  const expected = crypto.createHash(method).update(raw).digest('hex')
  return expected === sign
}

响应规范

HTTP 状态码说明
200接收成功,系统不再重推
非 200接收失败,系统按策略重试(是否重试、重试次数/间隔需要在平台侧配置,见下方注意事项)

注意事项

  1. 时间戳有效期: 建议拒绝距当前时间超过 5 分钟的请求
  2. Nonce 防重放: 建议记录已处理的 nonce,拒绝重复请求
  3. 幂等处理:callId 为唯一键,避免重复处理同一通话
  4. 快速响应: 接收方应在 5 秒内返回 200,超时系统会误判为失败并重推
  5. 失败重推: 推送失败(非 200)后是否重推、重推次数和间隔,是数字人侧的可选配置,默认可能关闭;如果你这边的接口偶尔会短暂不可用,建议主动联系平台开启并确认当前的重推参数。即使重推全部失败,也可以用系统集成文档中的「查询线索通话结果」/「批量查询线索」接口兜底核对遗漏的话单。
  6. 未接通是否推送: 默认情况下所有通话(含未接通 UNREACHED)都会推送话单;如果配置为"仅接通时推送",未接通的通话将不会收到回调,需要通过查询接口获取。如果你这边发现未接通的通话没有收到话单,请联系平台确认当前配置。
  7. 时序参考: 线索入队后通常约 3 秒内发起呼叫(用户手机端出现来电一般在 3-4 秒内);通话挂断后话单回调通常在约 40 秒内推送。具体耗时会随线路和系统负载波动,仅供参考。