SIP3 2026.2.1 API 使用详解

SIP3 2026.2.1 API 使用详解:Twig REST 全量端点、检索语法、会话明细五件套、PCAP 下载与脚本化对接实测。

SIP3SIPVoIPSIP32026/10/27

SIP3 2026.2.1 API 使用详解

目标:给出 SIP3 社区版 2026.2.1(deb 路线)Twig REST API 的完整实测面——端点清单、请求体结构、检索语法、会话数据四类端点的返回解析,以及 PCAP 下载与脚本化对接示例。全部回显在本机实测栈(主机名 sip3-server,API 经 nginx 反代于 80 端口 /api 路径)采集(实测日期 2026-10-27),OpenAPI 描述由 /api/v3/api-docs 现场拉取(Twig API 2026.2.1-05046a0)。

一、API 总览与访问入口

1.1 三个入口

入口地址实测状态用途
OpenAPI 描述http://10.89.59.10/api/v3/api-docs200机器可读全量端点定义,对接第一入口
Swagger UIhttp://10.89.59.10/api/swagger-ui/302 → 500本构建 UI 资产加载异常(见 8.3),用上一行为准
Hoof 界面http://10.89.59.10/200人工检索入口,底层就是本文这组 API

1.2 基础约定

  • Base URL:/api。nginx 把 /api/ 反代到 Twig 的 8080,Twig 自身 server.servlet.context_path: /api(见《SIP3 2026.2.1 配置参数详解》第五节),两者对齐后浏览器与脚本统一走 80 端口。
  • 认证:默认 security.enabled: false,一切请求以匿名身份获得管理员角色。GET /api/users/profile 实测:
root@pbx:~# curl -s http://10.89.59.10/api/users/profile
{"is_authenticated":true,"name":"anonymousUser","authorities":["ROLE_SIP3_ADMIN"]}

开启认证后 Twig 校验 Grafana 会话,profile 返回真实用户与角色(配置见《SIP3 2026.2.1 配置参数详解》Security 段)。

  • 编码:请求/响应均为 JSON(UTF-8),字段下划线命名(property_naming_strategy: SNAKE_CASE);时间字段统一为毫秒级 epoch 整数。

1.3 端点总表

/api/v3/api-docs 实测列出 24 个操作,按域分组:

域方法与路径说明
检索POST /search呼叫/注册会话检索(第四节)
会话POST /session/details、/session/flow、/session/content、/session/media、/session/pcap、/session/stash会话明细五件套 + 暂存
属性GET /attributes检索字段字典
主机GET PUT POST /hosts;POST /hosts/import;GET DELETE /hosts/{name};GET /hosts/addr/{addr};DELETE /hosts/{name}/all主机台账管理
组件GET /management/components;GET /management/components/latest;GET DELETE /management/components/{deploymentId};GET DELETE /management/components/name/{name};PUT …/shutdown;PUT …/recording-reset(按 id 与按 name 各一组)组件注册表与运维操作

二、检索:POST /api/search

2.1 请求体(SearchRequest,5 字段全部必填)

字段类型说明
created_atlong时间窗起点(毫秒 epoch)
terminated_atlong时间窗终点(毫秒 epoch)
querystring检索表达式(见 2.2),空串返回窗口内全部
limitint返回条数上限(Twig 侧 session.default_limit 默认 50)
fieldsarray附加返回字段清单(如 ["sip.duration"]),空数组即可

时间窗跨度过大或字段缺失会得到错误响应;窗口按记录的 created_at 匹配。

2.2 检索语法(实测两例)

表达式形如 字段=值,可用字段即 GET /api/attributes 字典里的清单(第五节)。实测 sip.method=INVITE 与 sip.caller=1001 均正常工作,后者返回窗口内全部主叫 1001 的会话。请求:

root@pbx:~# curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"created_at":1792982400000,"terminated_at":1793155200000,"query":"sip.method=INVITE","limit":10,"fields":[]}' \
  http://10.89.59.10/api/search
[{"method":"INVITE","state":"unknown","caller":"1001","callee":"1002","duration":null,"fields":null,"created_at":1793060842347,"terminated_at":1793060846888,"call_id":["test-call-004@10.89.59.1"],"error_code":null},{"method":"INVITE","state":"unknown","caller":"1001","callee":"1002","duration":null,"fields":null,"created_at":1793065927138,"terminated_at":1793065930978,"call_id":["bpf-test-002@10.89.59.1"],"error_code":null},{"method":"INVITE","state":"unknown","caller":"1001","callee":"1002","duration":null,"fields":null,"created_at":1793072299769,"terminated_at":1793072303978,"call_id":["b2-call-001@10.89.59.10"],"error_code":null}]

(本环境当日有三条 INVITE 测试记录,全量返回。)返回元素即 sip_call_index 集合的索引文档投影:call_id 是数组(一次呼叫可能有多个关联 ID),duration 为空表示单 INVITE 无完整媒体段,fields 镜像请求里的附加字段请求。

⚠️ 注意:没有 /api/sessions 这个端点。该错误路径实测返回 500(Twig 对未知 /api/* 路径的异常包装),不少旧资料以讹传讹,检索一律走 POST /api/search。

三、会话数据:POST /api/session/*

五个端点共用一个请求体结构(SessionRequest),核心字段:

字段类型说明
created_at / terminated_atlong时间窗(毫秒),必填
call_idarray呼叫 ID 列表,取自 /search 返回的 call_id 数组
methodarraySIP 方法列表(如 ["INVITE"]),与 call_id 配合定位会话
scr_addr / dst_addr / scr_host / dst_hoststring按地址/主机过滤(OpenAPI 原文即 scr_addr/scr_host,官方 schema 拼写如此,非笔误可改)
caller / callee / state / error_code / error_typestring按业务字段过滤
query / limitstring / int复合表达式与条数,可传空串/较大值

call_id 与 method 必须是数组——传字符串会得到空结果(2025.2.1 实测),Hoof 前端代码同样以 method:[e.method] 形态构造请求。以下均以 {"created_at":...,"terminated_at":...,"call_id":["test-call-004@10.89.59.1"],"method":["INVITE"],"query":"","limit":50} 为请求体(记作 $S)。

3.1 POST /api/session/details —— 报文明细

root@pbx:~# curl -s -X POST -H 'Content-Type: application/json' -d "$S" http://10.89.59.10/api/session/details
[{"created_at":1793060842347,"src_addr":"10.89.59.1","src_port":46410,"dst_addr":"10.89.59.10","dst_port":5060,"call_id":"test-call-004@10.89.59.1","request_uri":"sip:1002@10.89.59.10","from_uri":"sip:1001@10.89.59.1","to_uri":"sip:1002@10.89.59.10"}]

每条消息一元素:五元组地址端口、call_id 与三个 URI。排查「搜到了但打不开」先看这里有没有行。

3.2 POST /api/session/flow —— 呼叫流(界面 Call Flow 的数据源)

root@pbx:~# curl -s -X POST -H 'Content-Type: application/json' -d "$S" http://10.89.59.10/api/session/flow
{"participants":[{"name":"10.89.59.1","type":"host","details":{}},{"name":"10.89.59.10","type":"host","details":{}}],"events":[{"timestamp":1793060842347,"src":"10.89.59.1","dst":"10.89.59.10","type":"SIP","group":"test-call-004@10.89.59.1:z9hG4bK-test4:1","details":{"created_at":1793060842347,"src_addr":"10.89.59.1","src_port":46410,"dst_addr":"10.89.59.10","dst_port":5060,"parsed":true,"raw_data":"INVITE sip:1002@10.89.59.10 SIP/2.0\r\nVia: SIP/2.0/UDP 10.89.59.1:5060;branch=z9hG4bK-test4\r\nFrom: <sip:1001@10.89.59.1>;tag=abc444\r\nTo: <sip:1002@10.89.59.10>\r\nCall-ID: test-call-004@10.89.59.1\r\nCSeq: 1 INVITE\r\nContact: <sip:1001@10.89.59.1:5060>\r\nMax-Forwards: 70\r\nContent-Length:"}}

(输出节选(实测首尾):raw_data 为完整原始 SIP 报文,此处截断。)结构:participants 参与方 + events 时序事件(type=SIP/RTP/RTCP,group 为事务 ID,details 内嵌原始报文)。自绘时序图直接消费这个结构。

3.3 POST /api/session/content —— 报文列表视图

root@pbx:~# curl -s -X POST -H 'Content-Type: application/json' -d "$S" http://10.89.59.10/api/session/content
{"hosts":["10.89.59.1","10.89.59.10"],"messages":[{"created_at":1793060842347,"src_addr":"10.89.59.1","src_port":46410,"dst_addr":"10.89.59.10","dst_port":5060,"transaction_id":"test-call-004@10.89.59.1:z9hG4bK-test4:1","parsed":true,"raw_data":"INVITE sip:1002@10.89.59.10 SIP/2.0\r\nVia: SIP/2.0/UD

(输出节选(实测首尾):messages 为扁平消息数组。)与 flow 的区别:content 是无图形语义的平铺列表(hosts + messages),适合导出/归档。

3.4 POST /api/session/media —— 媒体质量

root@pbx:~# curl -s -X POST -H 'Content-Type: application/json' -d "$S" http://10.89.59.10/api/session/media
[]

本环境测试流量无 RTP,返回空数组属预期。有媒体会话时返回 RTP/RTCP 流指标(MOS、R 因子、丢包等,字段依据见《SIP3 2026.2.1 配置参数详解》codecs.yml 一节)。

3.5 POST /api/session/pcap —— 抓包下载

root@pbx:~# curl -s -X POST -H 'Content-Type: application/json' -d "$S" http://10.89.59.10/api/session/pcap -o session.pcap -w 'http=%{http_code} bytes=%{size_download}\n'
http=200 bytes=369
root@pbx:~# od -A d -t x1 -N 16 session.pcap
0000000 d4 c3 b2 a1 02 00 04 00 00 00 00 00 00 00 00 00
0000016

响应体就是 PCAP 文件(魔数 d4 c3 b2 a1 为小端 pcap 2.4,可用 Wireshark 直接打开)。这是取证排障的最后一环:从界面搜到呼叫 → API 拉原始抓包。

💡 技术拓展:OpenAPI 里还有一个 POST /api/session/stash(会话暂存),本环境未构造多会话暂存场景,未实测;语义可从 /api/v3/api-docs 的该端点定义读取。

四、属性字典:GET /api/attributes

检索表达式的「可用字段速查表」,同时给出类型与可选枚举:

root@pbx:~# curl -s http://10.89.59.10/api/attributes
[{"name":"sip.addr","type":"string","options":null},{"name":"sip.src_addr","type":"string","options":null},{"name":"sip.dst_addr","type":"string","options":null},{"name":"sip.user","type":"string","options":null},{"name":"sip.caller","type":"string","options":null},{"name":"sip.callee","type":"string","options":null},{"name":"sip.method","type":"string","options":["INVITE","REGISTER"]},{"name":"sip.call_id","type":"string","options":null},{"name":"sip.state","type":"string","options":["unknown"]},{"name":"sip.transactions","type":"number","options":null},{"name":"sip.retransmits","type":"numbe

(输出节选(实测首尾):后续还有 sip.duration 等字段。)options 非空即枚举字段——sip.method 只会出 INVITE/REGISTER(对应数据面开启的 feature),写检索表达式时以此为准,写错字段名得到空结果而非报错。启用 register/call 之外的 feature 后该字典会自动扩充。

五、主机台账:/api/hosts 系列

主机台账是界面上「按主机归组流量」的依据(对应 Captain 的 host 配置段,见《SIP3 2026.2.1 配置参数详解》4.3)。本环境未配置 host 清单,实测为空:

root@pbx:~# curl -s http://10.89.59.10/api/hosts
[]

可用操作:POST /api/hosts(单条登记)、POST /api/hosts/import(批量导入)、GET /api/hosts/addr/{addr}(按地址查)、GET|DELETE /api/hosts/{name}、DELETE /api/hosts/{name}/all。登记主机后,界面检索结果会带出主机名与角色标签,等价于在 Captain 侧配 host: 段——推荐二选一,避免两边维护。

六、组件管理:/api/management/components

组件注册表(管理通道 15091 的数据面视图)。实测:

root@pbx:~# curl -s http://10.89.59.10/api/management/components
[{"name":"sip3-salto","deployment_id":"22ec9a6d-85d0-434e-8234-298af58e14be","type":"salto","uri":["udp://0.0.0.0:15091","udp://0.0.0.0:15060"],"connected_to":["mongodb://127.0.0.1:27017/sip3"],"registered_at":1793065925925,"updated_at":1793075645925,"remote_updated_at":1793075645925,"config":{"name

(输出节选(实测首尾):config 内为该组件上报的完整生效配置,与启动日志一致。)字段解读:deployment_id 组件实例唯一标识;uri 双端口即管理 15091 + 数据 15060;connected_to 存储依赖自报;updated_at 心跳时间——排障时先看这个值是否持续推进(停更即组件假死)。

运维端点(危险操作,仅排障用):PUT /api/management/components/{deploymentId}/shutdown、PUT .../recording-reset(按 name 各一组),前者远程停组件、后者重置录音会话。GET 与 DELETE 同路径可查详情/删注册记录;GET /api/management/components/latest 返回最近心跳组件。

七、脚本化对接示例

一段可直接运行的 Python(检索最近 24 小时 INVITE 并下载第一条的 PCAP):

import requests, time

BASE = "http://10.89.59.10/api"
now = int(time.time() * 1000)

hits = requests.post(f"{BASE}/search", json={
    "created_at": now - 86_400_000,
    "terminated_at": now + 60_000,
    "query": "sip.method=INVITE",
    "limit": 10,
    "fields": []
}).json()

if hits:
    call_id = hits[0]["call_id"]          # 已是数组,直接回传
    pcap = requests.post(f"{BASE}/session/pcap", json={
        "created_at": hits[0]["created_at"],
        "terminated_at": hits[0]["terminated_at"],
        "call_id": call_id,
        "method": [hits[0]["method"]],
        "query": "", "limit": 50
    })
    open(f"{call_id[0]}.pcap", "wb").write(pcap.content)
    print("saved:", call_id[0], len(pcap.content), "bytes")

要点:call_id 从检索结果原样回传(保持数组);method 包一层列表;PCAP 响应直接写二进制。会话类端点时间窗建议覆盖检索时的 created_at/terminated_at,窗口不含该时间点会得到空结果。

八、错误路径与排障

8.1 /api/sessions 返回 500

不存在该端点。Twig 对未知 /api/* 路径的响应是 HTTP 500(异常包装),不是语义正确的 404,容易被误判为「服务坏了」。检索用 POST /api/search。

8.2 检索返回空数组

按序查三点:时间窗是否覆盖 created_at(毫秒,别用秒);表达式字段名是否在 /api/attributes 字典内;该字段值是否真实入库(可先用空 query 拉全量对照)。

8.3 Swagger UI 打不开(302 → 500)

/api/swagger-ui/ 重定向到 index.html 后资产加载 500,属本构建的前端资源问题,不影响机器对接——以 /api/v3/api-docs 为准(版本串实测 2026.2.1-05046a0)。需要图形化调试时可把 api-docs.json 导入 Apifox/Postman。

8.4 会话端点返回空

最常见原因是 call_id/method 传成了字符串(必须数组),或时间窗未覆盖该会话的 created_at;对照第三节请求体形态逐项检查。

九、参考链接