Webhook 参考
事半AI 平台向外部系统推送事件的 Webhook 说明——目前包含话单回调。
事半AI 平台通过 Webhook 主动向接入方推送事件。目前支持的事件如下:
| 事件 | 触发时机 | 说明 |
|---|---|---|
| 话单回调 | 一通电话结束后 | 推送该通通话的话单、意向结果与完整对话记录 |
话单回调(接入方实现)
通话结束后,系统主动向接入方推送话单(含通话记录、意向结果、对话日志)。
接入方需提供
| 配置项 | 说明 |
|---|---|
| 推送地址(url) | 接收话单的 HTTPS POST 接口地址 |
| 应用 ID(appId) | 标识接口调用方,也可用于区分业务 |
| 应用密钥(appSecret) | 用于签名验证 |
| 加密方法 | md5 或 sha256 |
请求 Header
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| Content-Type | string | ✓ | application/json |
| X-App-Id | string | ✓ | 应用 ID |
| X-Timestamp | int64 | ✓ | 当前时间戳(秒) |
| X-Nonce | string | ✓ | 随机字符串(防重放) |
| X-Sign | string | ✓ | 签名值 |
| X-Sign-Method | string | ✓ | md5 或 sha256 |
请求 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 导入"
}
字段可用性说明:
hangupType、answerStatus、answerMainStatus、wechatStatus、wechatSeatName、wechatSeatPhone、sipStatus这 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→ MD5X-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 | 接收失败,系统按策略重试(是否重试、重试次数/间隔需要在平台侧配置,见下方注意事项) |
注意事项
- 时间戳有效期: 建议拒绝距当前时间超过 5 分钟的请求
- Nonce 防重放: 建议记录已处理的 nonce,拒绝重复请求
- 幂等处理: 以
callId为唯一键,避免重复处理同一通话 - 快速响应: 接收方应在 5 秒内返回 200,超时系统会误判为失败并重推
- 失败重推: 推送失败(非 200)后是否重推、重推次数和间隔,是数字人侧的可选配置,默认可能关闭;如果你这边的接口偶尔会短暂不可用,建议主动联系平台开启并确认当前的重推参数。即使重推全部失败,也可以用系统集成文档中的「查询线索通话结果」/「批量查询线索」接口兜底核对遗漏的话单。
- 未接通是否推送: 默认情况下所有通话(含未接通
UNREACHED)都会推送话单;如果配置为"仅接通时推送",未接通的通话将不会收到回调,需要通过查询接口获取。如果你这边发现未接通的通话没有收到话单,请联系平台确认当前配置。 - 时序参考: 线索入队后通常约 3 秒内发起呼叫(用户手机端出现来电一般在 3-4 秒内);通话挂断后话单回调通常在约 40 秒内推送。具体耗时会随线路和系统负载波动,仅供参考。