系统集成文档
外部系统对接事半AI平台需要用到的全部接口——获取项目/数字员工信息、AI 外呼、AI 呼入、话术管理。通话结束后的话单回调请见 Webhook 参考。
目录
前置条件
对接前您需要确认:
- API 地址:
https://api.halfcall.cn - SIP 地址:
115.190.223.167:5080(AI 呼入接入用) - 认证方式:所有请求在 Header 携带
Authorization: Bearer <api_key>,Key 在后台 API Key 管理 页创建 - 数据格式:JSON,
Content-Type: application/json - 权限隔离:每个 API Key 只能操作自己企业下的数据
- SIP 白名单:走 AI 呼入前,业务方服务器出口IP需发送给管理员加入系统白名单,否则 SIP 请求会被拒绝
- 话单回调:通话结束后系统主动推送话单,配置方式与签名规则见 Webhook 参考
下文示例中 sk_xxx、cmk...(项目 ID)、bot_xxx(数字员工 ID)均为占位符,替换成您自己企业下的真实值。
一、获取基础信息
对接前,需先通过 API 获取 programId(项目 ID)和 botId(数字员工 ID),后续所有操作依赖这两个ID。
1.1 获取项目列表
GET /api/v1/external/programs
curl "https://api.halfcall.cn/api/v1/external/programs" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"total": 2,
"list": [
{
"programId": "cmkhndatf000jdulm6ez8ojyf",
"name": "事半AI客服",
"runState": "PAUSED",
"executionMode": "Stream"
}
]
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| total | 企业下项目总数 |
| programId | 项目唯一 ID,后续接口均需此值 |
| name | 项目名称 |
| runState | 运行状态:RUNNING=运行中,PAUSED=已暂停 |
| executionMode | 执行模式:Stream=流式自动外呼,Batch=手动批次模式 |
1.2 获取项目下数字员工列表
GET /api/v1/external/programs/:programId/bots
curl "https://api.halfcall.cn/api/v1/external/programs/cmk.../bots" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"bots": [
{
"botId": "bot_xxx",
"name": "小智",
"stage": 1,
"isEnabled": true,
"hotInitStatus": "NONE"
}
]
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| botId | 数字员工唯一 ID,AI 呼入时作为 X-BotId 传入,上传线索时指定 botId |
| name | 数字员工名称 |
| stage | 轮次序号,一个项目可配置多个数字员工按轮次依次跟进 |
| isEnabled | 是否启用,false 表示该数字员工已暂停 |
| hotInitStatus | 话术配置状态:NONE=正常可用,PENDING=升级排队,UPGRADING=升级中,FAILED=升级失败 |
1.3 查询线路状态
GET /api/v1/external/programs/:programId/line-status
查询项目当前线路使用情况,可用于判断是否有空闲线路可发起外呼。
curl "https://api.halfcall.cn/api/v1/external/programs/cmk.../line-status" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"programId": "cmk...",
"runState": "RUNNING",
"maxConcurrency": 50,
"currentConcurrency": 12,
"idle": 38
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| runState | 项目运行状态:RUNNING / PAUSED |
| maxConcurrency | 最大并发线路数 |
| currentConcurrency | 当前正在通话的线路数 |
| idle | 空闲线路数(maxConcurrency - currentConcurrency) |
小程序集成建议:在发起外呼前先调用此接口,当
idle > 0且runState = "RUNNING"时再推送线索。
1.4 获取线路列表
GET /api/v1/external/trunks
获取当前企业可读取到的线路——包含本企业名下的线路,以及对本企业开放的共享线路(不区分项目)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| status | string | - | 按线路状态筛选:Normal=可用,Band=已禁止,不传则不过滤 |
| page | number | - | 页码,默认 1 |
| pageSize | number | - | 每页数量,默认 20,最大 100 |
curl "https://api.halfcall.cn/api/v1/external/trunks" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"total": 2,
"page": 1,
"pageSize": 20,
"list": [
{
"trunkId": "trunk_xxx",
"name": "北京-移动专线",
"description": "示例线路",
"status": "Normal",
"trunkType": "SIP",
"operators": "CMCC",
"showPhoneType": "FixedLine",
"outerCaller": "010xxxxxxx",
"whitelistCity": "北京",
"concurrency": 50,
"callRate": 3000,
"startTime": "2024-01-01T00:00:00.000Z",
"endTime": "2024-12-31T23:59:59.000Z",
"scope": "own"
}
]
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| trunkId | 线路唯一 ID |
| status | 线路状态:Normal=可用,Band=已禁止 |
| trunkType | 线路类型:FreeSwitch / SIP / PhoneNumber / AX |
| operators | 运营商:CMCC=移动,CUCC=联通,CTCC=电信 |
| showPhoneType | 外显号码类型:FixedLine=固话,VirtualTrumpet=虚拟小号,RealnameMobile=实名手机 |
| outerCaller | 外显主叫号码 |
| whitelistCity | 限制城市 |
| concurrency | 线路并发数 |
| callRate | 每日拨打频次上限 |
| scope | own=本企业名下线路,shared=对本企业开放的共享线路 |
1.5 获取音色列表
GET /api/v1/external/voices
获取当前企业可读取到的音色(TTS 模型)——包含全局共享音色,以及本企业专属克隆音色,用于配置数字员工时参考。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| status | string | - | 按状态筛选:active=使用中,disabled=已停用,不传则不过滤 |
| page | number | - | 页码,默认 1 |
| pageSize | number | - | 每页数量,默认 20,最大 100 |
curl "https://api.halfcall.cn/api/v1/external/voices" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"total": 3,
"page": 1,
"pageSize": 20,
"list": [
{
"voiceModelId": "model_xxx",
"name": "佳音",
"model": "speech-2.8-hd",
"voice": "voice_id_xxx",
"price": 0.01,
"status": "active",
"scope": "shared",
"createdAt": "2024-01-01T00:00:00.000Z",
"bots": [
{ "botId": "bot_xxx", "name": "小智" }
]
}
]
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| voiceModelId | 音色对应的模型 ID,配置数字员工 TTS 时使用 |
| name | 音色名称 |
| model | 底层模型标识 |
| voice | 底层音色标识(voice_id) |
| price | 计费单价(元) |
| status | active=使用中,disabled=已停用 |
| scope | own=本企业专属音色,shared=全局共享音色 |
| bots | 当前使用该音色的本企业数字员工列表(botId + name) |
二、AI 外呼
线索排队与拨打机制说明(常见问题,建议先看一遍):
- 同号覆盖:同一手机号在同一天内重复推送线索(无论批量上传还是 2.3 实时单条),会覆盖当天已有的线索记录并重新置为待拨状态——即使旧记录已经拨打完成,也会被重新拉回排队。如果同一天同一号码有多个独立通知都需要送达(比如同一人当天多场会议),目前无法在同一
programId下同时保留多条待拨记录,请拆分到不同programId推送,或错开到不同自然日推送。- 暂停期间推送:项目处于
PAUSED时推送的线索会正常入队(状态WAITING),不会丢失,也无需重推;项目恢复RUNNING后会自动开始拨打这些线索。- 时段外排队:不在工作时段内推送的线索会保持排队,到下一个允许拨打时段自动补呼;目前没有过期时间(会一直排队到拨出或被撤销为止)。如果线索已经推送但临时不需要再拨了(比如会议被取消),可调用 2.8 撤销线索 撤回。
- 未接通重拨:平台内置随访重拨策略(默认关闭,需联系管理员开启),重拨的退避间隔与最大次数由平台侧配置,暂不支持通过 API 查询或修改。开启后,重拨产生的每一通电话都会作为独立记录出现在 2.5/2.7 查询接口返回的
calls[]里。建议提前和平台确认好重拨策略由哪边负责,避免和自建的重推逻辑重复打扰用户。
2.1 线索导入(批量上传)
步骤一:下载该数字员工的线索 Excel 模板
GET /api/v1/external/programs/:programId/leads/template
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| botId | string | - | 指定数字员工,不传则用项目第一个启用的数字员工 |
curl -O -J "https://api.halfcall.cn/api/v1/external/programs/cmk.../leads/template?botId=bot_xxx" \
-H "Authorization: Bearer sk_xxx"
返回 .xlsx 文件,第一行为表头(字段由数字员工话术配置决定),例如:
| 手机号码 | 姓名 | 公司名称 |
|---|---|---|
表头列名即为上传时的字段映射依据,请勿修改列名,否则上传会报字段不匹配错误。
步骤二:按模板填写数据后上传
POST /api/v1/external/programs/:programId/leads/upload
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| file | File | ✓ | Excel 或 CSV(.xls .xlsx .csv,最大 100MB) |
| botId | string | ✓ | 数字员工 ID,需与下载模板时一致 |
| name | string | - | 线索包名称,不传则用文件名 |
curl -X POST "https://api.halfcall.cn/api/v1/external/programs/cmk.../leads/upload" \
-H "Authorization: Bearer sk_xxx" \
-F "file=@/path/to/leads.xlsx" \
-F "botId=bot_xxx" \
-F "name=茅台外呼-第一批"
{
"code": 0,
"data": {
"threadId": "thread_xxx",
"name": "茅台外呼-第一批",
"total": 980,
"skipped": 20
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| threadId | 线索包唯一 ID,可用于后续查看该批次外呼进度 |
| name | 线索包名称 |
| total | 成功写入的线索数量 |
| skipped | 因同一项目下手机号重复被跳过的数量 |
2.2 查询线索字段定义
GET /api/v1/external/programs/:programId/leads/fields
在推送线索之前先调用一次,拿到该数字员工
variables需要传的准确字段 key(而不是 Excel 模板里看到的中文列名)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| botId | string | - | 指定数字员工,不传则用项目 stage 最小的已启用数字员工(与下载模板默认逻辑一致) |
curl "https://api.halfcall.cn/api/v1/external/programs/cmk.../leads/fields" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"programId": "cmk...",
"botId": "bot_xxx",
"fields": [
{ "key": "org_name", "name": "单位名称", "required": true },
{ "key": "contact_name", "name": "联络员姓名", "required": true },
{ "key": "meeting_title", "name": "会议主题", "required": true }
]
}
}
key就是 2.3 节variables里要用的字段名;name只是给人看的中文标签,不要把name当 key 传(会被拒绝,见下方校验说明)。
2.3 线索导入(实时单条)
POST /api/v1/external/leads
适合用户实时触发场景(如刚填写表单),立即入队等待外呼。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| programId | string | ✓ | 项目 ID |
| phone | string | ✓ | 手机号 |
| botId | string | - | 指定数字员工(用于按其字段定义做校验),不传则用项目 stage 最小的已启用数字员工 |
| variables | object | - | 自定义参数,key 必须是 2.2 节返回的 key(也兼容直接传 name,会自动转换,但不建议依赖这个兼容行为) |
curl -X POST "https://api.halfcall.cn/api/v1/external/leads" \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"programId": "cmkhndatf000jdulm6ez8ojyf",
"phone": "13800138000",
"variables": { "org_name": "示例公司", "contact_name": "张三" }
}'
{
"code": 0,
"threadId": "detail_xxx",
"phone": "13800138000",
"message": "Lead has been queued for processing"
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| threadId | 线索唯一 ID,可传入 GET /api/v1/external/leads?threadId= 查询后续通话结果 |
| phone | 已入队的手机号 |
| message | Lead has been queued for processing=新线索已入队;Lead already exists, re-queued for calling=手机号已存在,重新入队 |
字段校验:variables 会按该数字员工的字段定义校验——传了未知字段、或缺了必填字段,都会直接返回 400 并在 msg 里说明具体字段,线索不会入队。校验通过前后的 key 均按 2.2 节的 key 处理(若传的是 name 会被自动转换)。
2.4 启动项目
线索上传后,需启动项目才会开始外呼。
POST /api/v1/external/programs/:programId/run-state
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| action | string | ✓ | start=启动,pause=暂停 |
curl -X POST "https://api.halfcall.cn/api/v1/external/programs/cmk.../run-state" \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{"action": "start"}'
{ "code": 0, "data": { "programId": "cmk...", "runState": "RUNNING" } }
响应字段说明:
| 字段 | 说明 |
|---|---|
| programId | 操作的项目 ID |
| runState | 变更后的运行状态:RUNNING=已启动,PAUSED=已暂停 |
2.5 查询线索通话结果
通话结束后,可主动查询线索的通话记录和意向分析结果。
GET /api/v1/external/leads
# 方式1:通过推送线索时返回的 threadId
curl "https://api.halfcall.cn/api/v1/external/leads?threadId=detail_xxx" \
-H "Authorization: Bearer sk_xxx"
# 方式2:通过 programId + phone
curl "https://api.halfcall.cn/api/v1/external/leads?programId=cmk...&phone=13800138000" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"threadDetailId": "detail_xxx",
"phone": "13800138000",
"status": "COMPLETED",
"stage": 1,
"variables": { "name": "张三" },
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:01:30.000Z",
"calls": [
{
"callId": "call_xxx",
"reached": "REACHED",
"duration": 120,
"intention": "HIGH",
"intentionRate": 85,
"summary": "客户感兴趣,约好明天回电",
"recordingUrl": "https://cdn.halfcall.cn/rec/xxx.mp3",
"extractData": { "interested": true },
"createdAt": "2024-01-01T00:01:00.000Z"
}
]
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| threadDetailId | 线索唯一 ID |
| phone | 手机号 |
| status | 线索状态:PENDING=待拨打,CALLING=拨打中,COMPLETED=已完成,INVALID=无效 |
| stage | 当前所在轮次(对应数字员工的 stage) |
| variables | 推送线索时传入的自定义变量 |
| calls | 该线索的所有通话记录,按时间倒序 |
| calls[].reached | 接通状态,见下方枚举表 |
| calls[].duration | 通话时长(秒) |
| calls[].intention | AI 判断意向,见下方枚举表 |
| calls[].intentionRate | 意向评分(0-100) |
| calls[].summary | AI 生成的通话摘要 |
| calls[].recordingUrl | 通话录音地址,有效期 7 天 |
| calls[].extractData | AI 从对话中提取的结构化数据(由话术配置决定字段) |
calls[].reached 枚举值(2026-08 更新,此前版本文档写的 REACHED/NO_ANSWER/BUSY/FAILED 已过时,请以下表为准;"平台展示"列是登录 Web 工作台查看通话记录时看到的中文文案,方便和客服对话时对齐口径):
| 值 | 平台展示 | 含义 | 是否接通 |
|---|---|---|---|
REACHED | 已接听 | 通话进行中的中间态(尚未挂断)。通话结束后正常会落到下面三个终态之一,查询接口里较少见到停留在这个值上的记录 | 是 |
AGENT_END | 已接通-AI挂断 | 接通后由 AI 挂断 | 是 |
SEAT_END | 已接通-坐席挂断 | 接通后转人工,由坐席挂断 | 是 |
USER_END | 已接通-客户挂断 | 接通后由用户(被叫)挂断 | 是 |
UNREACHED | 响铃-未接听 | 已振铃,但用户未接听 | 否 |
CALL_REJECTED | 响铃-用户拒接 | 用户主动拒接 | 否 |
EMPTY_PHONE | 未接通-空号 | 空号 | 否 |
SHUTDOWN | 未接通-空号或关机 | 号码关机或空号 | 否 |
UN_CONNECT | 未打通 | 呼叫未能建立连接 | 否 |
INVALID | 未接通 | 未归入以上任何具体原因的无效通话 | 否 |
CALLER_ABNORMAL | 未接通-主叫异常 | 我方线路/主叫侧异常导致未接通 | 否 |
INIT / PREPARE / DIALED | 初始化 / 准备拨打 / 已拨打 | 拨打中间态,还没有最终结果 | - |
判断"是否接通"建议用
reached in [REACHED, AGENT_END, SEAT_END, USER_END],或者用duration > 0兜底。如果您同时登录了平台 Web 工作台查看通话记录,会看到"已接通"/"未接通"两个汇总筛选项——"已接通"就是上表"是否接通=是"的四个值汇总;"未接通"是除这四个值之外的全部其余状态(含
INIT/PREPARE/DIALED这类还没结果的中间态),比 API 语境里习惯理解的"未接通"范围更宽,两边对数据时注意口径差异。
calls[].intention 枚举值:NONE=未分析或不适用,REACHED=已接通但尚未分类,HIGH=高意向,HESITATE=犹豫,LOW_DIFFICULTY/HIGH_DIFFICULTY=意向分类(原文档 LOW 已废弃,这两个新值的具体业务含义正在和研发确认,暂按字面理解,后续版本会补充准确释义),UNKNOW=未知。
通话刚挂断时
intention可能短暂返回UNKNOW(AI 需要基于转写文本做后置分析,有几秒延迟),过几秒重查即可拿到最终结果。
2.6 拨打配置(可选)
GET /api/v1/external/programs/:programId/dialing-config — 查询当前配置
PUT /api/v1/external/programs/:programId/dialing-config — 修改配置(字段均可选,只传需要修改的)
curl -X PUT "https://api.halfcall.cn/api/v1/external/programs/cmk.../dialing-config" \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"maxConcurrency": 30,
"workTimeConfig": {
"callTimeSlots": [
{ "id": "slot-1", "start": 540, "end": 1080, "days": [1,2,3,4,5] }
]
}
}'
{
"code": 0,
"data": {
"programId": "cmk...",
"runState": "RUNNING",
"maxConcurrency": 30,
"priorityStrategy": "LIFO",
"workTimeConfig": {
"callTimeSlots": [
{ "id": "slot-1", "start": 540, "end": 1080, "days": [1,2,3,4,5] }
]
},
"blockStartTime": null,
"blockEndTime": null
}
}
字段说明:
| 字段 | 说明 |
|---|---|
| maxConcurrency | 最大并发通话数(1-500) |
| priorityStrategy | 线索拨打顺序:LIFO=后上传先拨(默认),FIFO=先上传先拨 |
| workTimeConfig.callTimeSlots[].start/end | 允许拨打的时间段,单位分钟(540=09:00,1080=18:00) |
| workTimeConfig.callTimeSlots[].days | 允许拨打的星期:1=周一,7=周日 |
| blockStartTime / blockEndTime | 绝对禁呼时段(分钟数),优先级高于 callTimeSlots |
2.7 批量查询线索
GET /api/v1/external/leads/batch
相比 2.5(每次只能查一条),本接口支持一次查询多条线索,或者按项目 + 日期批量拉取当天的拨打记录,适合替代逐条轮询、批量核对"哪些线索还没接通"。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| threadIds | string | 与 programId 二选一 | 逗号分隔的线索 ID 列表,最多 100 个 |
| programId | string | 与 threadIds 二选一 | 项目 ID,配合 date 按天拉取该项目下所有线索 |
| date | string | - | 日期(YYYY-MM-DD),仅支持按单日过滤,暂不支持起止时间范围 |
| page | number | - | 页码,默认 1 |
| pageSize | number | - | 每页数量,默认 20,最大 100 |
# 方式1:按线索 ID 列表批量查询
curl "https://api.halfcall.cn/api/v1/external/leads/batch?threadIds=detail_1,detail_2,detail_3" \
-H "Authorization: Bearer sk_xxx"
# 方式2:按项目 + 日期拉取当天的线索
curl "https://api.halfcall.cn/api/v1/external/leads/batch?programId=cmk...&date=2026-08-20" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"total": 128,
"page": 1,
"pageSize": 20,
"list": [
{
"threadDetailId": "detail_xxx",
"phone": "13800138000",
"programId": "cmk...",
"status": "COMPLETED",
"stage": 1,
"createdAt": "2026-08-20T09:00:00.000Z",
"updatedAt": "2026-08-20T09:03:00.000Z",
"latestCall": {
"callId": "call_xxx",
"reached": "USER_END",
"duration": 120,
"intention": "HIGH",
"intentionRate": 85,
"summary": "客户感兴趣,约好明天回电",
"createdAt": "2026-08-20T09:01:00.000Z"
}
}
]
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| total | 符合条件的线索总数 |
| list[].status | 线索状态,同 2.5 的 status |
| list[].latestCall | 该线索最近一次通话的摘要(只有最新一次,不含完整通话历史;需要某条线索的完整 calls[] 请用 2.5 按 threadId 单条查询) |
目前该接口没有额外的调用频率限制,但仍建议按需拉取(比如按 date 增量轮询),避免一次性拉取过大范围的数据。
2.8 撤销线索
POST /api/v1/external/leads/cancel
撤销尚未拨打(排队中)的线索,适合"线索已经推送,但情况有变不需要再打了"的场景(比如会议被取消)。只能撤销当前仍处于排队中的线索;已经开始拨打或已完成的线索不受影响,也不会报错。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| threadDetailId | string | 二选一 | 撤销单条线索(即 2.1/2.3 返回的线索 ID) |
| programId | string | 二选一 | 撤销该项目下当前全部排队中的线索(用于批量清空队列) |
# 撤销单条线索
curl -X POST "https://api.halfcall.cn/api/v1/external/leads/cancel" \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{ "threadDetailId": "detail_xxx" }'
# 撤销某项目下全部排队中的线索
curl -X POST "https://api.halfcall.cn/api/v1/external/leads/cancel" \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{ "programId": "cmk..." }'
{ "code": 0, "data": { "cancelled": 1 } }
响应字段说明:
| 字段 | 说明 |
|---|---|
| cancelled | 实际被撤销的线索数量 |
注意事项:
threadDetailId和programId只能二选一。- 按
threadDetailId撤销时,如果该线索已经开始拨打或已结束(不再是排队中),接口会返回409并说明当前状态,不会误撤正在进行或已完成的通话。 - 按
programId撤销时,只影响调用瞬间仍处于排队中的线索;如果撤销请求发出的同时某条线索恰好被自动拨号器拾取开始拨打,那一条会被跳过(不计入cancelled)。 - 撤销后的线索不会再出现在自动拨号队列里,但历史记录仍可通过 2.5/2.7 查询到(
status会变化)。
三、AI 呼入接入
3.1 参数说明
AI 呼入支持通过 SIP Header 传入自定义参数,系统接收后在提示词中替换对应变量,实现个性化呼入体验。参数需提前在平台配置好字段定义,以下为示例(实际字段以平台配置为准):
| 参数 KEY | 参数名称 | 说明 | 是否必须 |
|---|---|---|---|
| user_phone | 用户手机号 | 用户手机号 | ✓ |
| variable3 | 用户的姓名 | 用户的姓名 | ✓ |
| variable10 | 用户欠费的金额 | 用户欠费的金额 | ✓ |
| variable2 | 余额50需充值金额 | 余额50需充值金额 | ✓ |
| variable4 | 余额一百需充值金额 | 余额一百需充值金额 | ✓ |
| variable9 | 用户欠费的手机号 | 用户欠费的手机号 | ✓ |
3.2 SIP Header 说明
| Header | 必填 | 说明 |
|---|---|---|
sip_h_X-BotId | ✓ | AI 数字员工唯一标识(即 1.2 中获取的 botId) |
sip_h_X-Call-Params | ✓ | 呼入参数,JSON 对象经 Base64 编码后的字符串 |
sip_h_X-Call-ID | ✓ | 本次呼入的唯一标识,全局唯一;通话结束后可凭此 ID 通过回调或查询接口获取结果 |
origination_uuid | ✓ | 发起方 UUID,由贵方外呼系统生成 |
3.3 参数编码
将所有参数组成 JSON 对象,整体做 Base64 编码后放入 sip_h_X-Call-Params:
function encodeCallParams(params) {
return Buffer.from(JSON.stringify(params)).toString('base64')
}
const encoded = encodeCallParams({
user_phone: "18888888888",
variable3: "张三",
variable10: "150.00",
variable2: "200.00",
variable4: "250.00",
variable9: "18811111111",
})
// eyJ1c2VyX3Bob25lIjoiMTg4ODg4ODg4ODgiLCJ2YXJpYWJsZTMiOiLlvKDkuIkiLCJ2YXJpYWJsZTEwIjoiMTUwLjAwIiwidmFyaWFibGUyIjoiMjAwLjAwIiwidmFyaWFibGU0IjoiMjUwLjAwIiwidmFyaWFibGU5IjoiMTg4MTExMTExMTEifQ==
3.4 FreeSWITCH 转发示例
originate {
ignore_early_media=true,
origination_uuid=001
} user/1001 &bridge({
sip_h_X-BotId=85488662,
sip_h_X-Call-Params=eyJ1c2VyX3Bob25lIjoiMTg4ODg4ODg4ODgiLCJ2YXJpYWJsZTMiOiLlvKDkuIkiLCJ2YXJpYWJsZTEwIjoiMTUwLjAwIiwidmFyaWFibGUyIjoiMjAwLjAwIiwidmFyaWFibGU0IjoiMjUwLjAwIiwidmFyaWFibGU5IjoiMTg4MTExMTExMTEifQ==,
sip_h_X-Call-ID=callid_20250720_083123,
ignore_early_media=false,
origination_uuid=001
} sofia/external/sip:85488662@115.190.223.167:5080)
sip_h_X-Call-ID建议格式:callid_{yyyyMMdd}_{HHmmss}_{随机串},通话结束后可凭此 ID 通过回调接收或主动查询结果。
话单回调:通话结束后系统会主动向业务服务器推送话单(含通话记录、意向结果、对话日志),推送地址/签名规则/请求体等说明见 Webhook 参考。
四、话术管理(可选)
如需通过 API 动态更新数字员工的话术内容,可使用以下接口。
4.1 读取当前话术
GET /api/v1/external/bots/:botId/script
curl "https://api.halfcall.cn/api/v1/external/bots/bot_xxx/script" \
-H "Authorization: Bearer sk_xxx"
{
"code": 0,
"data": {
"botId": "bot_xxx",
"botName": "小智",
"scriptId": "script_xxx",
"scriptName": "茅台外呼话术",
"scriptVersion": 5,
"hotInitStatus": "NONE",
"prompt": "你是一名茅台集团的销售代表..."
}
}
响应字段说明:
| 字段 | 说明 |
|---|---|
| scriptVersion | 话术版本号,每次更新自动 +1,可用于判断是否有变更 |
| hotInitStatus | AI 配置状态:NONE=正常可用,PENDING=等待重新初始化,UPGRADING=初始化中,FAILED=初始化失败 |
| prompt | 话术原始提示词,即数字员工对话策略的源头文本 |
4.2 更新话术
PUT /api/v1/external/bots/:botId/script
curl -X PUT "https://api.halfcall.cn/api/v1/external/bots/bot_xxx/script" \
-H "Authorization: Bearer sk_xxx" \
-H "Content-Type: application/json" \
-d '{ "prompt": "你是一名茅台集团的销售代表..." }'
{ "code": 0, "msg": "success", "data": { "botId": "bot_xxx", "scriptId": "script_xxx" } }
注意: 话术更新后不会立即生效,需在平台手动触发"重新初始化"(
hotInitStatus变为PENDING),AI 重新生成配置后新话术才会被使用。
错误码
| code | HTTP 状态码 | 说明 |
|---|---|---|
| 0 | 200/201/202 | 成功 |
| -1 | 400 | 请求参数错误(如字段缺失、格式不符) |
| -1 | 401 | API Key 无效、已撤销或已过期 |
| -1 | 403 | 无权访问该资源(不属于当前企业) |
| -1 | 404 | 资源不存在 |
| -1 | 500 | 服务器内部错误 |