跳到正文

HTTP 接口文档

外呼派发接口背后的领取、容量、originate 与终态闭环见 外呼任务生命周期

callout-server 默认监听 0.0.0.0:9920。所有接口(除特别说明)都走会话鉴权,所有响应都用统一信封。

通用约定

响应信封

jsonc
// 成功
{ "code": "0000", "data": { /* ... */ }, "msg": "获取成功" }
// 失败
{ "code": "404", "data": null, "msg": "中文错误信息" }

三个顶层字段始终存在,成功码固定为字符串 "0000",失败码通常与 HTTP status 一致。SSE 事件、二进制下载、音频流和 OPTIONS 预检不套用 JSON 信封;业务数据内部 原本名为 ok 的字段保持不变。 HTTP 状态码:200 成功;400 参数错误;401 未鉴权/凭证无效;403 权限不足; 404 资源不存在;409 冲突(重复编码/忙碌中/锁竞争/非空删除);410 资源已过期; 500 服务端错误;502/503 下游(FreeSWITCH/Redis)不可用。

鉴权

启用鉴权(auth.enabled=true,默认)时:

  1. POST /api/auth/login 用用户名/密码换取 token
  2. 后续请求带 Authorization: Bearer <token>
  3. GET /api/auth/me 返回当前用户与其 permissions 列表(前端据此做菜单/按钮门控)。

本地联调可设 CALLOUT_AUTH_ENABLED=false 关闭鉴权。启用时自动创建引导管理员 (默认 admin / 见部署配置,可用 CALLOUT_AUTH_BOOTSTRAP_ADMIN_USERNAME/PASSWORD 覆盖)。

内部回写接口 /api/call-results/api/transfers/route/api/transfers/end/api/call-progress 不走会话鉴权,改用内部 token (请求头 X-Callout-Internal-Token,比对 internalApi.callResultToken;配置为空时放行)。

角色与权限矩阵

权限adminsupervisoragent
admin(用户/系统)
audit:read(审计)
line:write(线路)
campaign:write(任务)
campaign:dispatch(派发/会议监控/主管介入)
policy:write(策略)
compliance:write(DNC 合规)
import:write(导入)
contact:write(联系人/结果)
agent:write(坐席花名册管理)
agent:operate(坐席自助:状态/呼出/回拨/转人工/踢会议成员)

agent:write(管理坐席)与 agent:operate(坐席本人操作)刻意分离:坐席能操作软电话工作流,但不能管理花名册。

分页与搜索

列表接口普遍支持 ?page(默认 1)、?pageSize(默认 50,部分上限 200)、?q(全文搜索)。 分页响应统一为 { rows, page, pageSize, total }


鉴权与权限

POST /api/auth/login

请求:{ "username": "admin", "password": "******" } 响应 data

jsonc
{
  "token": "<bearer-token>",
  "expiresAt": "2026-06-16T09:00:00.000Z",
  "user": { "id": 1, "username": "admin", "displayName": "管理员", "role": "admin" },
  "permissions": ["admin", "campaign:write", ...]
}

POST /api/auth/logout

注销当前会话(请求头带 Bearer Token)。data 返回已注销用户摘要。

GET /api/auth/me

返回当前用户与权限;未登录或鉴权关闭时也会返回相应状态,供前端判断是否需要登录。

GET /api/roles/permissions

返回权限定义 + 角色→权限矩阵:{ permissions: PermissionDefinition[], roles: RolePermissionRow[] }


仪表盘与运行态

GET /api/nlu/capabilities

由 callout-server 使用服务端配置的 endpoint、内部 token 和超时代理统一 NLU 的能力发现接口。响应 data.actions 包含 decision / extract,每项提供 defaultProfileprofiles[{ key, labelZh, descriptionZh }]。下游超时返回 504,其它不可用或无效响应返回 502;浏览器不会接触 NLU token。

注意路径差异:本接口是 /api/nlu/capabilities(无 v1,callout-server 代理),下游是 llm-nlu-server 的 GET /api/v1/nlu/capabilities(有 v1,默认 :9930)。NLU 执行接口 POST /api/v1/nlu 由 callflow-esl 直连 llm-nlu-server,不经 callout-server。

方法路径权限说明
GET/health公开服务与数据库连通性
GET/api/overview会话数量、比率、近期活动/呼叫尝试
GET/api/overview/trend?days=14会话按天聚合的呼叫/结果趋势(days 默认 14,范围 1–90)
GET/api/media/config会话前端拼接录音和情绪复核音频播放地址所需的 baseUrl
GET/api/runtime/overview会话运行中并发、卡住联系人、各任务进度、各线路并发、近期运行事件
GET/api/runtime/events会话SSE 运行事件流(text/event-stream
PATCH/api/runtime/events/:id/acknowledge会话确认某条运行事件/告警
GET/api/audit-logs?page&pageSize&qaudit:read敏感操作审计日志

GET /api/runtime/overviewdataRuntimeOverviewResponse)含:activeContactsstuckContactsrunningBatchesscheduler.{submittedLastMinute,failedLastMinute,completedBatchesLastMinute}campaignProgress[]lineConcurrency[]cellConcurrency[](各 FS cell 的 { cellId, maxConcurrency, active }maxConcurrency 0 = 不限制)、stuckBatches[]recentEvents[]


业务编码(callflow 业务)

GET /api/businesses

列出 callflow 库中已启用call_businesses,供创建任务时选择 businessCodedata.rows: { id, businessCode, businessName, isEnabled, remark }[]


流程脚本 scripts

流程脚本是系统二的话术资产:前端可视化编排节点图(start / send / collect / router / chat / end / transfer),运行时由 callflow-esl 的 callout-flow-business 按 runtime 接口输出的 JSON 逐节点执行。NLU 与对话节点契约分别见 flow-script-nlu-development.mdflow-script-chat-development.md

方法路径权限说明
GET/api/v1/scripts会话列出流程脚本,供外呼活动选择与管理页展示
POST/api/v1/scripts会话创建或更新脚本(节点、变量、话术、NLU 分支、结果归类)
DELETE/api/v1/scripts/:id会话软删除脚本,保留历史引用
GET/api/v1/scripts/:id/runtime内部 token输出 callout-flow-business 执行用的运行时 JSON(最小字段集)

GET /api/v1/scripts/:id/runtime 不走会话鉴权:与 /api/call-results 一样比对 X-Callout-Internal-TokeninternalApi.callResultToken(配置为空时放行),供 callflow-esl 在通话内拉取。


外呼线路 lines

线路决定主叫号码与并发;任务必须绑定至少一条启用线路。

方法路径权限
GET/api/lines会话
POST/api/linesline:write(仅 admin)
PATCH/api/lines/:idline:write
DELETE/api/lines/:idline:write(仅软删未被引用的线路)

POST /api/lines 请求体(CreateLineInput):

jsonc
{
  "name": "默认外呼线路",
  "code": "default-trunk",
  "dialStringTemplate": "sofia/gateway/my-trunk/{{destinationNumber}}",
  "callerIdNumber": "01088886666",       // 可选,single_shared 模式默认主叫
  "callerIdName": "示例企业",             // 可选
  "maxConcurrency": 10,                   // 该线路下所有任务共享
  "allocationMode": "single_shared",      // single_shared | number_pool | bound_numbers
  "callerIdHeaderMode": "caller_id_only", // caller_id_only | p_preferred_identity | from_and_p_preferred_identity
  "numbers": [                            // number_pool / bound_numbers 模式的号码池
    { "number": "01088886601", "weight": 2, "maxConcurrency": 1, "isEnabled": 1 }
  ],
  "isEnabled": 1,
  "description": "..."
}

号码分配模式:single_shared(一号多并发)/ number_pool(多号轮换,按 weight)/ bound_numbers(一号一并发)。响应 data.line: CalloutLineRow(含 numbers[])。


外呼任务 campaigns

方法路径权限说明
GET/api/campaigns?page&pageSize&q会话列表(搜索+分页)
POST/api/campaignscampaign:write创建任务
GET/api/campaigns/:id会话详情:任务 + 联系人样本 + 近期呼叫尝试 + 批次
PATCH/api/campaigns/:idcampaign:write更新(状态/并发/重试/工作日/绑定线路/业务配置等)
DELETE/api/campaigns/:idcampaign:write软删空任务(非运行中且无联系人/批次/未软删尝试)
GET/api/campaigns/:id/preflight会话启动前预检:状态、计划窗口、待呼名单、线路、策略

POST /api/campaigns 请求体(CreateCampaignInput):

jsonc
{
  "name": "外呼平台演示任务",
  "businessCode": "callout-flow-business",           // 必须能在 call_businesses 查到启用记录
  "cellId": null,                                    // 可选;绑定 config.cells 声明的 FS cell,空 = 派发时自动分配
  "lineIds": [1],                                    // 至少一条启用线路
  "maxConcurrency": 5,
  "maxRetries": 2,
  "retryIntervalSeconds": 600,
  "callIntervalMs": 1000,
  "workdayStart": "09:00",          // 可选 HH:mm
  "workdayEnd": "20:00",
  "scheduledStartAt": null,
  "scheduledEndAt": null,
  "businessConfig": {
    "variables": { "script_id": "4" }               // 仅字符串值会注入通道变量
  },
  "description": "..."
}

PATCH /api/campaigns/:idstatus 改为 running 即启动(被调度器扫描);改 paused 暂停自动派发。 启动时若既无待呼/可重试联系人,也无活跃通话,返回 HTTP 409 且保留原状态;已归档任务同样 不可启动。等待未来重试或仍有活跃通话时允许保持/切换为 runningcellId 传字符串改绑 cell(须在 config.cells 中声明),传 null 或空串解绑。 businessConfig 使用整组替换语义,不接受旧的顶层 variables / intentKeywords。空的 variablesintentKeywords 会被省略。知识库实时盯屏任务可在业务专属配置中提交 { "businessCode": "kb-audio-chat-business", "businessConfig": { "intentKeywords": ["可以", "有兴趣"], "monitoringMode": "elastic", "monitoringPriority": 50 } }monitoringMode 支持 strict(无人时停止新派发)、elastic(允许 AI 无人值守)与 unattended;这两个监控属性只对 kb-audio-chat-business 生效,切换到其它业务时服务端会清理。

GET /api/campaigns/:iddataCampaignDetail):{ campaign, contacts[], contactTotal, attempts[], batches[] }


联系人 contacts

方法路径权限说明
GET/api/campaigns/:id/contacts?page&pageSize&q&status会话列表
POST/api/campaigns/:id/contactscontact:write粘贴号码同步导入,单次最多 10,000 行
PATCH/api/campaigns/:id/contacts/:contactIdcontact:write更新单个
DELETE/api/campaigns/:id/contacts/:contactIdcontact:write软删单个
POST/api/campaigns/:id/contacts/pausecontact:write批量暂停(避免运行中继续派发)
POST/api/campaigns/:id/contacts/deletecontact:write批量软删

POST /api/campaigns/:id/contacts 请求体(CreateContactsInput):

jsonc
{
  "contacts": [
    { "phoneNumber": "13800138000", "customerName": "王先生", "remark": "...",
      "metadata": { "orderId": "A123", "level": "vip" } }  // 仅字符串值会作为通道变量注入
  ]
}

响应与文件导入一致,包含 totalRows / createdRows / skippedRows / duplicateRows / failedRows / errorserrors 每项只有 { rowNumber, phoneNumber, reason };计数恒满足 totalRows = createdRows + duplicateRows + failedRowsskippedRows = duplicateRows + failedRows。 手工新增与粘贴入口不限制号码格式,只要求号码非空,并由服务端唯一索引最终去重。 CSV/TSV 文件导入仍按提交的地区、运营商和固话选项执行号码校验。


派发、批次与重试

方法路径权限说明
POST/api/campaigns/:id/dispatchcampaign:dispatch手动派发,最多 100 个待呼联系人
POST/api/campaigns/:id/retrycampaign:dispatch把匹配联系人重置为 pending
GET/api/campaigns/:id/batches?page&pageSize会话派发批次历史
POST/api/campaigns/:id/batches/:batchId/cancelcampaign:dispatch取消仍在 running 的批次
GET/api/call-attempts?page&pageSize&campaignId&status&callStatus&emotionStatus会话呼叫明细列表
GET/api/call-attempts/:attemptId会话按 ID 返回完整、未软删除的呼叫明细;不存在时返回 404

POST /api/campaigns/:id/dispatch 请求体 { "limit": 20 }(服务端 clamp 到 1..100)。 响应(DispatchCampaignResponsedata.resultDispatchResult):

jsonc
{
  "campaignId": 1, "batchId": 42,
  "requestedLimit": 20, "effectiveLimit": 20, "requested": 8,
  "submitted": 8, "failed": 0, "remainingPending": 12,
  "campaignStatus": "running",
  "attempts": [
    { "contactId": 100, "phoneNumber": "138...", "attemptId": 555,
      "status": "accepted", "requestId": "<uuid>", "replyText": "+OK ...",
      "callStatus": "answered",                 // 启用回铃检测时带
      "ringbackDetection": { "status": "answered", "detectionSource": "answer", ... } }
  ]
}
  • 派发可能被外呼策略拦截 → 409error 以「当前外呼策略禁止派发」开头。
  • 锁竞争 → 409「任务正在调度中」;Redis 锁不可用 → 503
  • 无可派发联系人 / 无可用槽位 / 呼叫间隔未到时不落批次,batchId 返回 nullrequested/submitted/failed 均为 0。

POST /api/campaigns/:id/retry 请求体(RetryContactsInput):

jsonc
{ "status": "failed" }                       // 或 { "contactIds": [1,2,3] }

把匹配联系人改回 pendingstatus 可取 failed/submitted/completed/paused


小批量同步文件导入

文件解析和号码校验先完成,再进入事务锁定 campaign 并按 1,000 行分批写入。除 running 外的任务状态均可导入;运行中返回 409,且不写入联系人。数据库异常会整体回滚。

方法路径权限说明
POST/api/campaigns/:id/import-filesimport:write上传最大 5 MiB、最多 10,000 行的 CSV/TSV 并同步返回结果

空文件、表头或列映射错误、未闭合 CSV 引号、超过 10,000 行返回 400;超过 5 MiB 返回 413。所有拒绝都发生在联系人事务写入前。JSON POST /import-jobs、导入历史、错误明细和 错误 CSV 接口已删除,不再保存逐行导入历史。


外呼策略 policies

全局/任务级禁呼、时段、号码规则、频控、重试与并发限制;执行语义更严格优先(全局与任务级都必须通过)。

方法路径权限
GET/api/policies?campaignId=会话
POST/api/policiespolicy:write
PATCH/api/policies/:idpolicy:write
DELETE/api/policies/:idpolicy:write
POST/api/policies/evaluate会话

POST /api/policies 请求体(CreateCalloutPolicyInput):

jsonc
{
  "name": "工作时段",
  "scope": "global",            // global | campaign(campaign 时需 campaignId)
  "type": "daily_window",
  "action": "allow_window",     // block | allow_window | limit
  "priority": 10,
  "config": { "start": "09:00", "end": "20:00" },
  "isEnabled": 1
}

策略类型 typeconfig

typeconfig 示例作用
blocked_dates{ "dates": ["2026-05-01"] }命中日期阻断
holiday_blocklist{ "dates":["2026-02-17"], "recurringDates":["01-01"], "workdayOverrides":["2026-02-14"], "region":"CN" }节假日阻断 + 补班放行
daily_window{ "start":"09:00", "end":"20:00" }仅允许每日时段
weekly_window{ "days":[1,2,3,4,5], "start":"09:00", "end":"18:00" }仅允许星期时段
phone_blacklist{ "numbers":["138...","139..."] }按号码阻断
phone_prefix_blocklist{ "prefixes":["170","171"] }按前缀阻断
contact_frequency_limit{ "days":7, "maxAttempts":2 }N 天最大触达次数
rate_limit{ "callIntervalMs":2000 }收紧呼叫间隔
retry_rule{ "maxRetries":1, "retryIntervalSeconds":1800 }收紧重试
concurrency_limit{ "maxConcurrency":3 }收紧并发

POST /api/policies/evaluate 试算(PolicyEvaluationRequestPolicyEvaluationResult):

jsonc
// 请求
{ "campaignId": 1, "phoneNumber": "13800138000", "at": "2026-06-15T03:00:00.000Z" }
// 响应 data
{ "allowed": false, "reason": "命中策略:工作时段(当前不在允许时段)",
  "matchedPolicies": [ /* CalloutPolicyRow */ ],
  "effectiveLimits": { "maxConcurrency": 3, "maxRetries": 1, "retryIntervalSeconds": 1800, "callIntervalMs": 2000 } }

DNC 免打扰名单

派发前独立于策略表进行阻断;业务回写退订/拒呼时自动沉淀。

方法路径权限
GET/api/dnc?page&pageSize&q会话
POST/api/dnccompliance:write
DELETE/api/dnc/:idcompliance:write

POST /api/dnc{ "phoneNumber": "138...", "reason": "客户要求", "expiresAt": null }expiresAt 为空=永久)。


结果回写(内部)

POST /api/call-results

内部接口(token 鉴权,非会话)。由 callflow-esl 业务在通话结束时回写。 完整字段、定位规则、时长推导、DNC 自动沉淀见 outbound-business-example.md。最小示例:

http
POST /api/call-results
Content-Type: application/json
X-Callout-Internal-Token: <internalApi.callResultToken>

{ "requestId": "<callout_request_id>", "callStatus": "completed",
  "payload": { "result": { "recognizedText": "客户有意向" } } }

实时盯屏与人工介入 live-calls

坐席「一人盯多路、有意向即插入」的实时监控链路。数据源是 callflow-esl 的 kb-audio-chat-business 在通话过程中逐轮上报的进度事件写入 Redis TTL 共享快照, 并通过 Pub/Sub 向每个实例的本机 SSE 客户端广播。Redis 是必选依赖,服务启动时连接失败会 直接退出,不提供内存降级。快照不写业务库(挂机后的整段回写 /api/call-results 仍是权威数据)。链路与配置 详见 transfer-to-human.md §盯屏介入 与业务文档 callflow-esl/docs/existing-businesses.md

方法路径权限说明
POST/api/call-progress内部 tokencallflow-esl 逐轮上报通话进度(started/segment/intervention/ended),更新共享快照并广播
GET/api/live-calls?campaignIdagent:operate当前用户实际获配及介入前保留只读通话的快照与全局容量摘要
GET/api/live-calls/events?campaignIdagent:operate多路复用 SSE:推送实际获配及保留只读通话的字幕/关键词/介入/归属变化事件
POST/api/live-monitor/heartbeatagent:operate登记并续租盯屏 Presence,按坐席实时状态计算接管容量并触发重分配
DELETE/api/live-monitor/presenceagent:operate主动离开盯屏并立即释放分配;异常断线由 TTL 回收
POST/api/live-calls/:callKey/interveneagent:operate坐席认领人工介入,信号转发给 callflow-esl(原子抢占,重复认领返回 409)
POST/api/live-calls/:callKey/intervention/cancelagent:operate仅介入发起人取消仍为 requested 的请求;已消费进入转接返回 409
POST/api/live-calls/:callKey/releaseagent:operate当前监控责任人主动让出;本次页面 Presence 生命周期内不再分回本人
POST/api/live-calls/:callKey/hangupcampaign:dispatch主管/管理员以 NORMAL_CLEARING 结束整通客户业务,成功操作写审计与运行事件
  • callKey 形如 attempt:<attemptId>(或 request:<requestId>)。
  • segment 事件的 speaker 取值:bot(AI 播报)/ customer(客户 ASR)/ agent(人工介入后坐席的会议转写);介入成功后坐席与客户的发言仍持续上报。
  • 意向关键词在 campaign 的 businessConfig.intentKeywords 中配置;收到客户 ASR 片段命中 任一关键词时,SSE 推 intent-alert 事件,盯屏页高亮 + 提示音。
  • 每路通话只分配一个主监控人;分配按 businessConfig.monitoringPriority、意向命中、等待时间、 坐席 cell 与页面任务过滤执行。同一登录用户的多个标签页合计仍受服务端容量限制。
  • 介入期间只保留介入通话的实际责任,其余原获配通话以 monitorViewMode=retained 继续只读展示; monitorAssignment 可为 null(等待接管)或指向另一坐席。介入结束后保留视图自动清除。
  • strict 任务会把活跃盯屏容量加入任务/线路/cell 的派发上限计算;无人时联系人保持待呼。
  • 介入生效有节点边界延迟(业务播完当前录音/收音后才转接),典型 3~10 秒。
  • Redis 已启用但不可用时,快照、SSE 建连和介入返回 503,不会退化为各实例分裂的本地状态。

坐席与软电话 agents

方法路径权限说明
GET/api/agents会话坐席 + 坐席组列表
GET/api/agents/extensions会话FreeSWITCH 可用分机(含 freeswitchReachable
GET/api/agents/phone-statusesagent:operate全部坐席的非敏感注册摘要:agentId / phoneExtension / registrationStatus;四态为 registered / unregistered / unconfigured / unknown
POST/api/agent-groupsagent:write创建坐席组
PATCH/DELETE/api/agent-groups/:groupIdagent:write更新/删除坐席组
POST/api/agentsagent:write创建坐席
PATCH/DELETE/api/agents/:idagent:write更新/删除坐席(忙碌中不可删)
GET/api/agents/me/statusagent:operate当前用户绑定且启用的坐席状态及电话注册态摘要;未绑定时 agent: null
PATCH/api/agents/me/statusagent:operate切换本人绑定坐席状态,仅接受 idle / busy / offline;电话仅在 registered(可用)时才能切到非离线状态
PATCH/api/agents/:id/statusagent:operate切换 idle / busy / offline;普通坐席仅能修改本人,主管/管理员可修改全部;旧 online 请求兼容映射为 idle;电话仅在 registered(可用)时才能切到非离线状态
POST/api/agents/:id/callbacksagent:operate人工回拨:originate 坐席分机后 bridge 客户
POST/api/agents/:id/manual-callsagent:operate人工呼出任意客户号码
POST/api/agents/:id/transfersagent:operate工作台对客户号码发起坐席↔客户桥接呼叫(≠AI会议转人工,见 transfer-to-human.md §7)

坐席公开结构只包含唯一终端标识 phoneExtension,不再返回 sipUsername。升级兼容期内, 创建/更新接口仍会把旧请求中单独出现的 sipUsername 映射到 phoneExtension;两个非空值 不一致时返回 400,禁止静默选择。 | GET | /api/softphone-calls?page&pageSize&agentId&campaignId | agent:operate | 软电话呼出/回拨/转人工记录 |

POST /api/agents/:id/manual-calls 请求体:

jsonc
{ "phoneNumber": "13800138000", "campaignId": 1, "contactId": 100, "note": "..." }
// 也可只传 contactId,号码从联系人取

回拨/呼出会经 submitAgentBridgeCall 先 originate 坐席分机、接通后 &bridge 客户号码, 并落 agent_call_records 记录(direction=callback/manual_call)。


浏览器软电话会话 softphone-sessions

坐席浏览器 SIP 软电话链路:整体流程、坐席 SIP 字段、配置与 FreeSWITCH 侧要求见 softphone-sip.md。callout-server 在这组接口上做权限校验与 agent_call_records 落库,实时会话本体代理到 callflow-esl 的 browser-softphone-session-hub

方法路径权限说明
GET/api/agents/me/sip-configagent:operate当前登录坐席的浏览器 SIP 注册配置(坐席与用户按 agents.userId 一对一绑定)
GET/api/agents/sip-configsagent:operate当前用户可见的已启用 SIP 配置列表(admin / supervisor 可见全部)
POST/api/softphone-sessionsagent:operate创建会话:先落 agent_call_records,再请求 callflow-esl 创建实时会话;返回 sessionIdserviceNumber 与浏览器拨号必须原样携带的 sipExtraHeaders
GET/api/softphone-sessions/:sessionId/eventsagent:operateSSE 实时事件流(session / message / tts / error);EventSource 场景支持 ?access_token= 查询参数鉴权
POST/api/softphone-sessions/:sessionId/messagesagent:operate坐席打字文本,经 TTS 注入客户腿播放
POST/api/softphone-sessions/:sessionId/controlsagent:operate控制命令:{"type":"hold"} / resume / {"type":"dtmf","digits":"..."} / {"type":"transfer","targetNumber":"..."}
POST/api/softphone-sessions/:sessionId/notesagent:operate更新会话备注
POST/api/softphone-sessions/:sessionId/endagent:operate结束会话(同时结束会议与录音收尾)
GET/api/softphone-calls/:softphoneCallIdagent:operate坐席通话记录详情:消息时间线、TTS 事件、录音信息与分角色转写

转人工会议 conference-sessions

详见 transfer-to-human.md

方法路径权限说明
POST/api/transfers/route内部 tokenAI 业务转人工路由:预占空闲坐席 + originate 入会(callflow-esl 调用)
POST/api/transfers/end内部 token客户挂机幂等收尾:校验客户 UUID,结束会议全部坐席/主管腿并释放坐席
GET/api/conference-sessionscampaign:dispatch进行中会话列表(附 FS 实时成员数)
GET/api/conference-sessions/:conferenceIdcampaign:dispatch会话详情 + 成员腿
POST/api/conference-sessions/:conferenceId/participantsagent: agent:operate / supervisor: campaign:dispatch加成员(坐席盲转/协商转 或 主管监听/强插)
DELETE/api/conference-sessions/:conferenceId/participants/:softphoneCallIdagent:operate踢出一名成员腿

录音与转写

方法路径权限说明
GET/api/media/config会话返回兼容默认值 freeswitchRecordingBaseUrl、按 cell 映射 freeswitchRecordingBaseUrlsByCellemotionAudioBaseUrl
GET/api/call-attempts/:attemptId会话返回单条完整呼叫明细;记录不存在或已软删除时返回 404
GET/api/call-attempts/:id/transcript-segments会话按外呼尝试查询分角色转写片段
POST/api/call-attempts/deletecompliance:write批量软删通话记录,并清除 contacts.lastAttemptId

外呼录音由业务回写到 call_attempts.recordingUrl,数据库和呼叫尝试 API 响应都只保留文件名短值;前端按 attempt.cellIdfreeswitchRecordingBaseUrlsByCell 选择前缀,历史空 cell 使用兼容默认值,非空失效 cell 不生成错误 URL。情绪分析 worker 使用相同规则。情绪分析音频仍用 emotionAudioBaseUrl 和短值拼接。



用户管理 users

方法路径权限说明
GET/api/users?page&pageSize&qadmin列表
POST/api/usersadmin创建
PATCH/api/users/:idadmin改角色/启停/重置密码
DELETE/api/users/:idadmin软删(禁止删自己或最后一个管理员)

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。