KuvaszUptime 4.6.0 REST API 实战指南
KuvaszUptime 4.6.0 REST API 实测手册:X-API-KEY 与 Bearer 双认证、v2/v3 端点布局,六类监控器 CRUD、心跳上报、事故与备注、状态页、维护窗口、YAML 导入导出与分页过滤约定,全部请求响应 JSON 实测回显,附 401/405/400 排障实录。
KuvaszUptime 4.6.0 REST API 实战指南
目标:以实测方式讲透 KuvaszUptime(项目名 Kuvasz)4.6.0 的 REST API——API Key 认证两种写法、v2/v3 双版本端点布局、六类监控器与事故/状态页/维护窗口的增删改查、监控器 YAML 导入导出与分页过滤约定,全部请求与响应 JSON 均为真实回显照抄。已在 Ubuntu 26.04.1 LTS(x86_64,Kuvasz 4.6.0)实测实例上逐条执行,服务端口 8141。部署与配置背景见《KuvaszUptime 4.6.0 Docker Compose 部署指南》与《KuvaszUptime 4.6.0 配置参数详解》。
一、环境信息
本篇所有请求均在以下环境实测,回显逐行照抄(长响应标注节选):
- 操作系统:Ubuntu 26.04.1 LTS(x86_64)
- Kuvasz 版本:4.6.0(
GET /api/v2/settings实测返回versionInfo.installedVersion: 4.6.0、isUpToDate: true) - API 基地址:
http://127.0.0.1:8141(远程访问把地址换成http://<服务器IP>:8141) - API Key:
kuvasz-demo-api-key-2026(部署时经ADMIN_API_KEY注入,最少 16 位) - 管理账号:
admin/q1w2e3r4q1w2e3r4(Web 会话认证用) - 客户端工具:curl 8.x(系统自带)、python3(格式化 JSON 用)
- 实测存量对象:HTTP 监控器
yaml-managed-site(id=5,YAML 管理)、Push 监控器nightly-backup(id=3)、TCP 监控器local-postgres(id=2)、Slack 集成ops-channel-demo(YAML 声明)
二、前置条件
2.1 服务端点与客户端工具
Kuvasz 的 REST API 与 Web 界面同端口同基地址(本环境为 8141),所有接口路径以 /api/ 开头。确认服务可达(health 端点免认证,可兼作拨测目标):
curl -s http://127.0.0.1:8141/api/v2/health
实测输出:
{"name":null,"status":"UP","details":null}
客户端用 curl 即可覆盖全部场景;浏览器打开 http://<服务器IP>:8141/api-docs 可访问内置的 OpenAPI 文档界面(Swagger UI),官方完整规范文件见文末参考链接。
2.2 认证凭据准备
API Key 在部署时通过 ADMIN_API_KEY 环境变量注入(不设则 API Key 认证整体关闭,见《KuvaszUptime 4.6.0 配置参数详解》5.1 节)。本篇统一使用 shell 变量减少重复:
KEY='kuvasz-demo-api-key-2026'
BASE='http://127.0.0.1:8141'
💡 说明:本篇为演示环境所以 Key 直接落明文;生产环境的 Key 属系统级凭据,建议在部署层注入而非写进脚本与文档。
三、API 总览
3.1 版本与协议约定
Kuvasz 4.6.0 同时提供两个 API 版本,按资源读写分工:
| 版本 | 定位 | 实测覆盖的端点形态 |
|---|---|---|
/api/v2/… | 主力版本:全部资源的增删改查、详情、统计、事件、导入导出 | 监控器六类、事故、状态页、维护窗口、集成、设置、健康 |
/api/v3/… | 列表查询增强版:统一分页信封 + 过滤/排序参数,当前仅覆盖列表与事件查询 | http/tcp/icmp/dns/docker/push-monitors、incidents、status-pages、maintenance-windows |
约定细节实测归纳:
- 请求与响应均为 JSON(导入导出等少数端点为 YAML / multipart 文件),
Content-Type: application/json; - 写操作成功:POST 返回
201,PATCH 返回200,DELETE 返回204(无响应体); - 错误响应统一形态:
{"message":"…","errorCode":null}或带_embedded.errors的 HAL 风格错误体,配套 400/401/404/405 状态码; - 时间戳全部带时区偏移(本环境为
+08:00,取决于服务端TZ); - 无官方限流约定,接口面向管理台场景设计。
3.2 端点清单(按域分组)
官方 OpenAPI 规范(kuvasz-latest.yml)中的全部路径,按域归纳如下({monitorId} 等为路径参数):
| 域 | 端点(v2 为主) | 方法 |
|---|---|---|
| 健康 | /api/v2/health | GET |
| 设置 | /api/v2/settings | GET |
| HTTP 监控器 | /api/v2/http-monitors、/api/v2/http-monitors/{monitorId} | GET/POST/PATCH/DELETE |
| 监控器统计与事件 | …/{monitorId}/stats、…/{monitorId}/uptime-events、…/{monitorId}/ssl-events(HTTP 独有) | GET |
| Push 心跳 | /api/v2/push-monitors/heartbeats/{clientSecret}(GET/POST)、…/heartbeats/{clientSecret}/failure(POST) | GET/POST |
| ICMP/TCP/DNS/Docker 监控器 | /api/v2/{icmp|tcp|dns|docker}-monitors…(同 HTTP 的 CRUD 结构) | GET/POST/PATCH/DELETE |
| 事故 | /api/v2/incidents、/api/v2/incidents/{incidentType}/{eventId} | GET |
| 事故备注 | /api/v2/incidents/{incidentType}/{eventId}/notes(POST/GET)、/api/v2/incidents/notes/{incidentNoteId}(PATCH/DELETE) | POST/GET/PATCH/DELETE |
| 状态页 | /api/v2/status-pages、/{statusPageId}、/{statusPageId}/details | GET/POST/PATCH/DELETE |
| 维护窗口 | /api/v2/maintenance-windows、/{maintenanceWindowId} | GET/POST/PATCH/DELETE |
| 集成 | /api/v2/integrations、/api/v2/integrations/{integrationId}/test | GET/POST |
| 导入导出 | /api/v2/monitors/export/yaml、/api/v2/monitors/import/yaml(状态页、维护窗口有同名对) | GET/POST |
| 指标 | /api/v2/prometheus(启用 Prometheus exporter 后可用) | GET |
| v3 列表 | /api/v3/{资源}-monitors、/api/v3/incidents 等 | GET |
3.3 认证方式
同一把 API Key 有两种等效携带方式,另有 Web 会话与免认证两类特例(第四章逐个实测):
| 方式 | 写法 | 实测结论 |
|---|---|---|
| 请求头(推荐) | -H "X-API-KEY: <key>" | 200 |
| Bearer | -H "Authorization: Bearer <key>" | 200,等效 |
| Web 会话 | 登录后浏览器持有的 JWT Cookie | 可调 API(4.4 节) |
| 免认证 | 仅 /api/v2/health 与心跳上报端点 | 见各节实测 |
四、认证与首次调用
4.1 无凭据与错误凭据:401 实测
不带任何凭据请求受保护端点:
curl -s $BASE/api/v2/monitors/export/yaml
实测输出(完整响应体):
{"message":"Unauthorized","_embedded":{"errors":[{"message":"Unauthorized","_embedded":{},"_links":{},"logref":null,"path":null}]},"_links":{"self":{"deprecation":null,"href":"/api/v2/monitors/export/yaml","hreflang":null,"name":null,"profile":null,"templated":false,"title":null,"type":null}},"logref":null,"path":null}
实测状态码:
401
Key 错误同样 401(响应体同上,self.href 随请求路径变化):
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: wrong-key-value-123" $BASE/api/v2/monitors/export/yaml
HTTP 401
4.2 X-API-KEY 与 Bearer 实测
两种写法各请求一次导出端点(完整导出内容见第十章),先看状态码:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/monitors/export/yaml
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -H "Authorization: Bearer $KEY" $BASE/api/v2/monitors/export/yaml
实测输出:
HTTP 200
HTTP 200
X-API-KEY 响应体开头(节选,YAML 格式):
---
http-monitors:
- name: "yaml-managed-site"
url: "https://www.example.org"
sensitive-url: false
uptime-check-interval: 300
enabled: true
ssl-check-enabled: true
latency-history-enabled: true
request-method: "GET"
follow-redirects: true
cross-origin-header-propagation: false
本篇后续统一用 X-API-KEY。
4.3 免认证端点
/api/v2/health 无需任何凭据(2.1 节已实测)。另有一类「凭据藏在路径里」的特殊端点:Push 心跳上报接口的路径参数是监控器的 clientSecret 而非请求头(7.1 节实测),这是为备份脚本等无头环境设计的免配置上报方式。
4.4 Web 会话认证
浏览器登录后颁发的 JWT Cookie 同样可调 API。实测先用表单登录拿会话:
curl -s -i -X POST -d 'username=admin&password=q1w2e3r4q1w2e3r4' $BASE/auth/login
实测响应头(节选):
HTTP/1.1 303 See Other
location: /
Set-Cookie: JWT=eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJrdXZhc3oiLCJzdWIiOiJhZG1pbiIsIm5iZiI6MTc5MzUxNjU1NiwiZXhwIjoxNzkzNjAyOTU2LCJpYXQiOjE3OTM1MTY1NTYsInJvbGVzIjpbIlJPTEVfV0VCIiwiUk9MRV9BUEkiXX0.eTh2eJz8--0y3wOLWds_TwIcw1HjiIO_ALhWyTNV1uw; Max-Age=86400; Expires=Mon, 02 Nov 2026 07:02:36 GMT; Path=/; HTTPOnly
JWT 载荷解码后含 "roles":["ROLE_WEB","ROLE_API"]——Web 会话同时具备 API 角色,把该 Cookie 随 -b 携带即可调用 API(实测成功返回 settings JSON)。注意三点:口令错误时同样返回 303(重定向回登录页,靠无 Cookie 判断失败);/login 本身不支持 API 式 POST JSON(实测 POST /login 返回 405 Method Not Allowed,只接受表单);JWT 有效期即配置的会话时长(默认 86400 秒)。
五、设置与系统信息 API
GET /api/v2/settings 一次返回认证、应用参数生效值、只读状态、指标导出、版本自检五块信息(参数含义见《KuvaszUptime 4.6.0 配置参数详解》),实测完整回显:
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/settings
{"authentication":{"enabled":true,"accessTokenMaxAge":86400,"oidc":null},"app":{"version":"4.6.0","eventDataRetentionDays":365,"latencyDataRetentionDays":7,"language":"en","eventLoggingEnabled":true,"editabilityState":{"areHttpMonitorsReadOnly":true,"areStatusPagesReadOnly":false,"arePushMonitorsReadOnly":false,"areIcmpMonitorsReadOnly":false,"areTcpMonitorsReadOnly":false,"areDnsMonitorsReadOnly":false,"areDockerMonitorsReadOnly":false,"areMaintenanceWindowsReadOnly":false},"updateChecksEnabled":true,"httpCheckTimeoutSeconds":30,"httpCheckMaxRedirects":10,"virtualThreadSchedulingEnabled":true},"metricsExport":{"exportEnabled":false,"meters":{"sslExpiry":false,"httpLatestLatency":false,"httpUptimeStatus":false,"sslStatus":false,"pushUptimeStatus":false,"icmpUptimeStatus":false,"icmpLatestLatency":false,"icmpLatestPacketLoss":false,"tcpUptimeStatus":false,"tcpLatestLatency":false,"dnsUptimeStatus":false,"dnsLatestLatency":false,"dockerUptimeStatus":false,"dockerLatestLatency":false,"dockerLatestCpuUsage":false,"dockerLatestMemoryUsage":false,"dockerLatestRestartCount":false},"exporters":{"prometheus":{"enabled":false,"descriptions":true},"openTelemetry":{"enabled":false,"url":"","step":"PT1M"}}},"mcpServer":{"enabled":false},"connectivityCheck":null,"smtp":null,"versionInfo":{"installedVersion":"4.6.0","latestVersion":"4.6.0","latestVersionDetails":"https://kuvasz-uptime.dev/changelog#4.6.0","isUpToDate":true}}
实操价值最高的两个字段:app.editabilityState(哪些资源类型正被 YAML 冻结,直接影响第六章写操作能否成功)与 versionInfo(升级判断)。
六、HTTP 监控器 API(CRUD 全流程)
HTTP 监控器的完整生命周期:创建 → 查询 → 更新 → 统计/事件 → 删除。每一步都给出实测请求与响应。
6.1 YAML 冻结态下的写操作:405 实测
先看反面教材——本环境 kuvasz.yml 定义了 HTTP 监控器,HTTP 类型整体冻结(editabilityState.areHttpMonitorsReadOnly: true,见第五章)。此时创建请求:
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"name":"http-api-demo","url":"https://www.example.org","uptimeCheckInterval":60}' \
$BASE/api/v2/http-monitors
实测输出:
{"message":"The given type of monitors were configured via a YAML file. You cannot modify them via the API. Please change the configuration in the YAML file and restart the server.","errorCode":null}
HTTP 405
PATCH/DELETE 同样被拒。解冻方法:把 http-monitors 段从 kuvasz.yml 移除并重启服务(该段导出的监控器转由数据库管理、数据不丢),实测重启后 editabilityState 全部恢复可写:
{"areHttpMonitorsReadOnly": false, "areStatusPagesReadOnly": false, "arePushMonitorsReadOnly": false, "areIcmpMonitorsReadOnly": false, "areTcpMonitorsReadOnly": false, "areDnsMonitorsReadOnly": false, "areDockerMonitorsReadOnly": false, "areMaintenanceWindowsReadOnly": false}
⚠️ 注意:何时该把监控器写进 YAML 是一个选型决策(IaC 唯一事实源 vs 界面/API 动态管理),冻结机制的两方向实测与恢复方法详见《KuvaszUptime 4.6.0 配置参数详解》5.6 节。本篇为演示 API 全流程,在解冻态完成以下操作,操作完成后已恢复原配置。
6.2 创建:POST 返回 201
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"name":"http-api-demo","url":"https://www.example.org","uptimeCheckInterval":60,"sslCheckEnabled":true,"sslExpiryThreshold":20,"failureCountThreshold":2,"expectedKeyword":"Example Domain","category":"demo"}' \
$BASE/api/v2/http-monitors
实测输出(完整响应,201 Created;id 由服务端分配):
{
"id": 23,
"name": "http-api-demo",
"url": "https://www.example.org",
"sensitiveUrl": false,
"uptimeCheckInterval": 60,
"enabled": true,
"sslCheckEnabled": true,
"requestMethod": "GET",
"latencyHistoryEnabled": true,
"forceNoCache": true,
"followRedirects": true,
"crossOriginHeaderPropagation": false,
"proxy": null,
"sslExpiryThreshold": 20,
"failureCountThreshold": 2,
"integrations": [],
"expectedStatusCodes": [],
"responseTimeThresholdMillis": null,
"expectedKeyword": "Example Domain",
"expectedKeywordCaseSensitive": false,
"expectedKeywordNegated": false,
"requestHeaders": {},
"expectedHeaders": {},
"requestBody": null,
"createdAt": "2026-11-01T15:59:21.412714+08:00",
"updatedAt": "2026-11-01T15:59:21.412714+08:00",
"category": "demo",
"ignoreConnectivityCheck": false
}
只传必填项也可创建(name + url 必填,其余落默认值)。
6.3 校验错误:缺必填字段返回 400
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"name":"no-url-demo"}' $BASE/api/v2/http-monitors
实测输出(节选,报错点名缺失字段):
HTTP 400
{"message":"Invalid JSON","_embedded":{"errors":[{"message":"Invalid JSON: Instantiation of [simple type, class com.kuvaszuptime.kuvasz.models.dto.monitor.http.HttpMonitorCreateDto] value failed for JSON property url due to missing (therefore NULL) value for creator parameter url which is a non-nullable type ...
6.4 查询:单个与列表
查询单个(路径参数用创建时返回的 id):
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/http-monitors/23
实测输出(节选 11 个关键字段):
{
"id": 23,
"name": "http-api-demo",
"url": "https://www.example.org",
"uptimeCheckInterval": 60,
"sslCheckEnabled": true,
"sslExpiryThreshold": 20,
"expectedKeyword": "Example Domain",
"failureCountThreshold": 2,
"category": "demo",
"enabled": true,
"uptimeStatus": null
}
uptimeStatus: null 表示首轮检查尚未发生;首轮检查完成后再查会变为 "UP"(或 "DOWN")。列表查询 GET /api/v2/http-monitors 返回同结构的数组(含运行态字段 uptimeStatus、sslStatus、lastUptimeCheck、nextUptimeCheck、sslValidUntil 等)。
6.5 更新:PATCH 返回 200
curl -s -X PATCH -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"name":"http-api-demo-renamed","uptimeCheckInterval":120}' \
$BASE/api/v2/http-monitors/23
实测输出(节选,PATCH 只提交要改的字段):
{
"id": 23,
"name": "http-api-demo-renamed",
"uptimeCheckInterval": 120,
"expectedKeyword": "Example Domain",
"updatedAt": "2026-11-01T15:59:21.483224+08:00"
}
6.6 统计与事件:stats 与 uptime-events
创建后等一个检查周期(60 秒间隔,实测等约 75 秒),取统计:
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/http-monitors/23/stats
实测输出(完整回显):
{"id":23,"latencyHistoryEnabled":true,"latencyStats":{"averageLatencyInMs":4053,"minLatencyInMs":4053,"maxLatencyInMs":4053,"p90LatencyInMs":4053,"p95LatencyInMs":4053,"p99LatencyInMs":4053},"uptimeHistory":{"period":"PT24H","incidents":0,"affectedMonitors":0,"uptimeRatio":1.0,"totalDowntimeSeconds":0},"latencyLogs":[{"id":38,"latencyInMs":4053,"createdAt":"2026-11-01T16:00:24.546862+08:00"}]}
解读:latencyStats 给平均/最小/最大与 p90/p95/p99 分位延迟;uptimeHistory 是 24 小时窗口的可用率(uptimeRatio: 1.0 即 100%);latencyLogs 是逐次延迟明细(受 latencyHistoryEnabled 开关控制)。
在线事件流:
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/http-monitors/23/uptime-events
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/http-monitors/23/ssl-events
实测输出:
[{"id":4,"status":"UP","error":null,"startedAt":"2026-11-01T16:00:24.550718+08:00","endedAt":null,"updatedAt":"2026-11-01T16:00:24.550718+08:00"}]
[]
endedAt: null 表示该 UP 事件仍在进行中;ssl-events 为空数组是本轮检查尚未产出 SSL 事件所致(存量监控器的 ssl-events 实测返回过 {"id":2,"status":"VALID",...,"sslValidUntil":"2026-12-26T06:13:27+08:00",...},结构同 uptime-events 多一个 sslValidUntil 字段)。
6.7 删除:DELETE 返回 204
curl -s -X DELETE -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/http-monitors/23
HTTP 204
删除后该监控器及其历史一并清除,再查返回 404。查询不存在的 id 的实测错误体:
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/http-monitors/6
HTTP 404
{"message":"There is no monitor with ID: 6","errorCode":null}
6.8 恢复 YAML 冻结(环境还原)
把 http-monitors 段加回 kuvasz.yml 并重启,实测 yaml-managed-site 以原 id=5 重新被 YAML 接管,areHttpMonitorsReadOnly 恢复 true:
http-monitors 列表:[(5, 'yaml-managed-site')]
{"areHttpMonitorsReadOnly": true, ...}
七、其他监控器类型 API
7.1 Push 监控器与心跳上报
Push 监控器是「主动心跳」型:被监控方按间隔主动上报,超时未收到即判 DOWN。创建(clientSecret 最少 36 位,实测短值无法通过校验):
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"name":"api-push-demo","heartbeatInterval":300,"gracePeriod":60,"clientSecret":"push-apidemo-0123456789abcdef-0123456789"}' \
$BASE/api/v2/push-monitors
实测输出(201 Created,节选):
{
"id": 25,
"name": "api-push-demo",
"heartbeatInterval": 300,
"gracePeriod": 60,
"clientSecret": "push-apidemo-0123456789abcdef-0123456789",
"enabled": true
}
心跳上报(免认证、免请求体,secret 即凭据;成功/失败两个端点):
# 成功心跳
curl -s -X POST -o /dev/null -w 'HTTP %{http_code}\n' $BASE/api/v2/push-monitors/heartbeats/push-apidemo-0123456789abcdef-0123456789
# 查询最近心跳(GET 同路径)
curl -s -X GET -o /dev/null -w 'HTTP %{http_code}\n' $BASE/api/v2/push-monitors/heartbeats/push-apidemo-0123456789abcdef-0123456789
# 显式失败信号
curl -s -X POST -o /dev/null -w 'HTTP %{http_code}\n' $BASE/api/v2/push-monitors/heartbeats/push-apidemo-0123456789abcdef-0123456789/failure
实测输出:
HTTP 202
HTTP 202
HTTP 202
上报成功心跳后查监控器,lastHeartbeat 与状态已更新(节选):
{"id": 25, "name": "api-push-demo", "lastHeartbeat": "2026-11-01T16:01:25.461246+08:00", "uptimeStatus": "UP"}
随后上报的失败信号立即产生事故(见第八章)。Push 统计端点实测:
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/push-monitors/25/stats
{"id":25,"uptimeHistory":{"period":"PT24H","incidents":1,"affectedMonitors":1,"uptimeRatio":null,"totalDowntimeSeconds":0}}
清理:
curl -s -X DELETE -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/push-monitors/25
HTTP 204
7.2 ICMP / TCP / DNS 监控器
三类监控器的 CRUD 与 HTTP 同构(POST /api/v2/{icmp|tcp|dns}-monitors → 201,PATCH → 200,DELETE → 204),差异只在业务字段:
| 类型 | 必填/特色字段 | 创建请求体示例(实测通过) |
|---|---|---|
| ICMP(ping 型) | host | {"name":"api-icmp-demo","host":"1.1.1.1","uptimeCheckInterval":60,"packetCount":3,"timeoutSeconds":5,"packetLossThreshold":100} |
| TCP(端口型) | host + port | {"name":"api-tcp-demo","host":"1.1.1.1","port":53,"uptimeCheckInterval":60,"timeoutMs":5000} |
| DNS(解析型) | host + 解析器 + 记录匹配器 | {"name":"api-dns-demo","host":"example.org","resolverHost":"1.1.1.1","resolverPort":53,"transport":"UDP","expectedResponseCode":"NOERROR"} |
三条创建请求实测均返回 201,响应结构与其他类型一致(含 uptimeCheckInterval、failureCountThreshold、metricsHistoryEnabled 等公共字段)。TCP 监控器的 stats 实测回显(含逐次延迟与分位):
{"id":15,"metricsHistoryEnabled":true,"uptimeHistory":{"period":"PT24H","incidents":0,"affectedMonitors":0,"uptimeRatio":1.0,"totalDowntimeSeconds":0},"latencyStats":{"averageLatencyInMs":245,"minLatencyInMs":245,"maxLatencyInMs":245,"p90LatencyInMs":245,"p95LatencyInMs":245,"p99LatencyInMs":245},"metricsLogs":[{"id":72,"latencyInMs":245,"createdAt":"2026-11-01T15:07:45.517504+08:00"}]}
DNS 监控器支持期望响应码(NOERROR 等)与记录匹配器断言;Docker 监控器依赖先配置的 Docker 主机(/api/v2/docker-hosts,本环境实测为空数组 []),本篇不展开。
八、事件、事故与备注 API
8.1 事故查询:v2 平铺与 v3 分页
GET /api/v2/incidents 返回全量平铺数组,实测共 3 条,首条(failure 信号产生的那条):
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/incidents
{
"monitorId": 25,
"monitorName": "api-push-demo",
"isMonitorEnabled": true,
"incidentType": "PUSH",
"eventId": 9,
"status": "ONGOING",
"details": "Reason: Client signaled an explicit failure",
"startedAt": "2026-11-01T16:01:25.510209+08:00",
"endedAt": null,
"updatedAt": "2026-11-01T16:01:25.510209+08:00"
}
status 两种取值:ONGOING(进行中)与 RESOLVED(已恢复,带 endedAt)。心跳恢复类事故的实测样例(历史上 nightly-backup 漏心跳事故在心跳恢复后自动闭合):
{"monitorId": 3, "monitorName": "nightly-backup", "incidentType": "PUSH", "eventId": 4, "status": "RESOLVED", "details": "Reason: Missed heartbeat", "startedAt": "2026-11-01T13:47:51.613339+08:00", "endedAt": "2026-11-01T15:06:50.554028+08:00", ...}
v3 版本改用分页信封(11 章详解):
curl -s -H "X-API-KEY: $KEY" "$BASE/api/v3/incidents?page=1&size=2"
实测回显(节选):
keys: ['result', 'page', 'size', 'totalCount', 'totalPages']
pageInfo: {"page": 1, "size": 2, "totalCount": 3, "totalPages": 2}
first item monitorName: api-push-demo ONGOING
8.2 事故详情:GET /api/v2/incidents/{incidentType}/{eventId}
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/incidents/PUSH/9
实测输出(完整回显,详情在事故之上叠加备注与关联集成):
{"incident":{"monitorId":25,"monitorName":"api-push-demo","isMonitorEnabled":true,"incidentType":"PUSH","eventId":9,"status":"ONGOING","details":"Reason: Client signaled an explicit failure","startedAt":"2026-11-01T16:01:25.510209+08:00","endedAt":null,"updatedAt":"2026-11-01T16:01:25.510209+08:00"},"notes":[],"integrations":[],"resolutionIntegrations":null}
事故类型 incidentType 与监控器类型对应(实测样例有 PUSH;HTTP/TCP 等类型的停机同样进事故列表)。查询不存在的事故返回 404,实测报文:{"message":"There is no PUSH incident with event ID: 9","errorCode":null}。
8.3 事故备注 CRUD
备注用于值班记录排查进展,可标记 public 同步展示到状态页。创建:
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"content":"值班开始排查,疑似备份脚本未按计划执行","status":"INVESTIGATING","public":true}' \
$BASE/api/v2/incidents/PUSH/9/notes
实测输出(201 Created):
{"id":2,"incidentType":"PUSH","eventId":9,"status":"INVESTIGATING","content":"值班开始排查,疑似备份脚本未按计划执行","timestamp":null,"public":true,"createdAt":"2026-11-01T16:01:25.615195+08:00","updatedAt":"2026-11-01T16:01:25.615195+08:00"}
status 是备注级的事故阶段标记(实测可用 INVESTIGATING / IDENTIFIED 等),PATCH 更新:
curl -s -X PATCH -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"content":"确认为脚本超时,已手工补跑","status":"IDENTIFIED"}' \
$BASE/api/v2/incidents/notes/2
实测输出(节选):
{"id":2,"incidentType":"PUSH","eventId":9,"status":"IDENTIFIED","content":"确认为脚本超时,已手工补跑","public":true,"createdAt":"2026-11-01T16:01:25.615195+08:00","updatedAt":"2026-11-01T16:01:25.675134+08:00"}
删除:
curl -s -X DELETE -H "X-API-KEY: $KEY" -o /dev/null -w 'HTTP %{http_code}\n' $BASE/api/v2/incidents/notes/2
HTTP 204
⚠️ 排障实录:实测有一次 DELETE 备注漏带
-H "X-API-KEY: …",返回401而非预期 204——所有/api/v2/incidents/notes/*操作都要认证头,心跳类端点才免认证。备注功能可用配置参数整体停用(停用后本节接口返回 405,见《KuvaszUptime 4.6.0 配置参数详解》5.3 节)。
九、状态页与维护窗口 API
9.1 状态页创建与详情
创建状态页(monitors 数组引用要展示的监控器):
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"title":"API Demo Status Page","slug":"api-demo-status","public":false,"monitors":["tcp:local-postgres"],"themeBase":"GRAY"}' \
$BASE/api/v2/status-pages
实测输出(201 Created):
{"id":2,"title":"API Demo Status Page","slug":"api-demo-status","customLogoUrl":null,"customFaviconUrl":null,"public":false,"monitors":["tcp:local-postgres"],"categories":[],"displayCategories":true,"themeBase":"GRAY","createdAt":"2026-11-01T16:01:53.557581+08:00","updatedAt":"2026-11-01T16:01:53.557581+08:00"}
monitors 引用格式是 type:name 复合串。写成数字 id 会被拒绝,实测:
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"title":"bad","slug":"bad","monitors":[2],"themeBase":"GRAY"}' $BASE/api/v2/status-pages
HTTP 400
{"message":"Invalid monitor ID format: 2. Expected format is 'type:name'.","errorCode":null}
对外渲染视角用 details 端点(节选):
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/status-pages/2/details
{
"id": 2,
"title": "API Demo Status Page",
"slug": "api-demo-status",
"public": false,
"systemStatus": "OPERATIONAL",
"historyDays": 30
}
systemStatus 汇总所含监控器状态;historyDays 即配置参数篇提到的「保留期 <30 天会同步缩短状态页历史窗口」的落点。清理:
curl -s -X DELETE -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/status-pages/2
HTTP 204
9.2 维护窗口 CRUD
维护窗口用 cron 表达式 + ISO-8601 时长定义计划性停机豁免:
curl -s -X POST -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"name":"api-mw-demo","enabled":true,"global":true,"showOnStatusPages":true,"cron":"0 3 * * *","duration":"PT30M"}' \
$BASE/api/v2/maintenance-windows
实测输出(201 Created):
{"id":2,"name":"api-mw-demo","description":null,"enabled":true,"global":true,"showOnStatusPages":true,"cron":"0 3 * * *","start":null,"duration":"PT30M","monitors":[],"categories":[],"integrations":[],"active":false,"nextStart":"2026-11-02T03:00:00+08:00","endsAt":null,"createdAt":"2026-11-01T16:01:53.452021+08:00","updatedAt":"2026-11-01T16:01:53.452021+08:00"}
字段解读:cron: "0 3 * * *" 每天 03:00 触发;duration: "PT30M" 持续 30 分钟;global: true 对全部监控器生效(也可用 monitors/categories 数组圈定范围);服务端已算好 nextStart。更新与删除:
curl -s -X PATCH -H "X-API-KEY: $KEY" -H "Content-Type: application/json" \
-d '{"description":"每日凌晨备份窗口"}' $BASE/api/v2/maintenance-windows/2
实测输出(节选):
{
"id": 2,
"name": "api-mw-demo",
"description": "每日凌晨备份窗口",
"cron": "0 3 * * *",
"duration": "PT30M",
"nextStart": "2026-11-02T03:00:00+08:00"
}
curl -s -X DELETE -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/maintenance-windows/2
HTTP 204
十、导入导出与集成 API
10.1 监控器 YAML 导出
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/monitors/export/yaml
实测输出(本环境全量,节选 http 与 push 两段;icmp/tcp/dns 段结构同构):
---
http-monitors:
- name: "yaml-managed-site"
url: "https://www.example.org"
sensitive-url: false
uptime-check-interval: 300
enabled: true
ssl-check-enabled: true
latency-history-enabled: true
request-method: "GET"
follow-redirects: true
cross-origin-header-propagation: false
proxy: null
force-no-cache: true
ssl-expiry-threshold: 30
failure-count-threshold: 1
integrations: []
expected-status-codes: []
response-time-threshold-millis: null
expected-keyword: null
expected-keyword-case-sensitive: false
expected-keyword-negated: false
request-headers: {}
expected-headers: {}
request-body: null
category: null
ignore-connectivity-check: false
push-monitors:
- name: "nightly-backup"
heartbeat-interval: 3600
grace-period: 0
client-secret: "push-0123456789-abcdefghijklmnopqrstuvwxyz"
enabled: true
integrations: []
failure-count-threshold: 1
category: null
ignore-connectivity-check: false
导出的就是规范的全字段 kebab-case YAML,可直接粘贴进 kuvasz.yml 完成迁移(注意导入某类型后该类型即冻结,见 6.1 节)。
10.2 监控器 YAML 导入:multipart 文件上传
导入接口接收 multipart 文件字段。先看手写精简 YAML 的失败实测——ICMP 段缺必填字段:
# import-demo.yml
icmp-monitors:
- name: imported-icmp-demo
host: 9.9.9.9
uptime-check-interval: 300
curl -s -X POST -H "X-API-KEY: $KEY" -F "file=@import-demo.yml" $BASE/api/v2/monitors/import/yaml
实测输出(HTTP 400,节选,报错精确到字段与行号):
{"message":"Failed to parse the uploaded YAML file: Missing required creator property 'packet-count' (index 3)\n at [Source: (byte[])\"icmp-monitors:\n - name: imported-icmp-demo\n host: 9.9.9.9\n uptime-check-interval: 300\n\"; line: 5, column: 1] (through reference chain: com.kuvaszuptime.kuvasz.models.dto.importing.MonitorImportDto[\"icmp-monitors\"]->java.util.ArrayList[0]->com.kuvaszuptime.kuvasz.models.dto.monitor.icmp.IcmpMonitorExportDto[\"packet-count\"]) ...
改用「先导出后导入」的完整格式(字段齐全)即可成功:
# import-demo2.yml(导出格式样例)
icmp-monitors:
- name: "imported-icmp-demo"
host: "9.9.9.9"
uptime-check-interval: 300
packet-count: 3
timeout-seconds: 5
packet-loss-threshold: 100
failure-count-threshold: 1
enabled: true
integrations: []
metrics-history-enabled: true
category: null
ignore-connectivity-check: false
curl -s -X POST -H "X-API-KEY: $KEY" -F "file=@import-demo2.yml" $BASE/api/v2/monitors/import/yaml
实测输出(HTTP 200):
{"dryRun":false,"perTypeResults":[{"monitorType":"ICMP","receivedCnt":1,"imported":["icmp:imported-icmp-demo"],"deleted":[],"ignoredIntegrations":[]}]}
核对导入结果:
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/icmp-monitors | python3 -c "import json,sys; print([(m['id'], m['name'], m['host']) for m in json.load(sys.stdin)])"
[(27, 'imported-icmp-demo', '9.9.9.9')]
清理导入对象:
curl -s -X DELETE -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/icmp-monitors/27
HTTP 204
状态页与维护窗口各有同名导入导出对(/api/v2/status-pages/export/yaml、/api/v2/maintenance-windows/import/yaml 等),机制相同。
10.3 集成查询与测试通知
集成列表(YAML 声明的 Slack 集成,标识为 type:name 复合 id):
curl -s -H "X-API-KEY: $KEY" $BASE/api/v2/integrations
实测输出:
[{"id":"slack:ops-channel-demo","type":"SLACK","name":"ops-channel-demo","enabled":false,"global":true,"excludedEvents":[]}]
发送测试通知(用演示 webhook,预期失败但验证了链路):
curl -s -X POST -H "X-API-KEY: $KEY" $BASE/api/v2/integrations/slack:ops-channel-demo/test
实测输出(HTTP 200,success: false 属预期——演示 webhook 地址非真实频道,Slack 端返回 no_team):
{"success":false,"message":"Test notification failed with error: no_team"}
真实 webhook 下该接口返回 {"success":true,...},是验收通知链路的标准动作。
10.4 Prometheus 指标端点
启用 Prometheus exporter 后 GET /api/v2/prometheus 输出文本格式指标。未启用时实测:
curl -s -o /dev/null -w 'HTTP %{http_code}\n' -H "X-API-KEY: $KEY" $BASE/api/v2/prometheus
HTTP 404
响应体为 {"message":"Not Found","_embedded":...}。启用方法与 17 项指标开关见《KuvaszUptime 4.6.0 配置参数详解》5.8 节。
十一、分页/过滤/排序通用约定(v3)
v3 列表端点统一分页信封与查询参数。实测 TCP 监控器列表(启用过滤 + 按名称倒序):
curl -s -H "X-API-KEY: $KEY" "$BASE/api/v3/tcp-monitors?enabled=true&sortedBy=name&sortOrder=desc&page=1&size=5"
实测回显(节选):
page/size/total: 1 5 1
items: [(2, 'local-postgres')]
信封字段与参数约定(对全部 v3 列表端点一致):
| 项 | 说明 | 实测取值 |
|---|---|---|
result | 数据数组 | 各资源对象 |
page / size | 当前页码与页大小 | 1 / 2 |
totalCount / totalPages | 总条数与总页数 | 3 / 2 |
page、size 参数 | 分页,默认 page=1 | ?page=1&size=2 |
enabled 参数 | 按启用状态过滤 | enabled=true |
sortedBy + sortOrder | 排序字段与方向 | sortedBy=name&sortOrder=desc |
v2 列表端点(如 GET /api/v2/incidents)无分页信封、返回平铺数组,量大时优先用 v3。
十二、常见问题(FAQ)
Q1:返回 401 的排查路径?
按序核对三点:请求是否带了认证头(实测漏带 -H "X-API-KEY: …" 即 401,见 8.3 节排障实录);Key 值是否与部署注入的 ADMIN_API_KEY 一致(实测错 Key 与无 Key 报错完全相同,都是 Unauthorized,不区分「没带」与「带错」);该端点是否本就免认证(health、心跳上报),免认证端点带不带头都能通。
Q2:返回 405「You cannot modify them via the API」?
该监控器类型正被 kuvasz.yml 冻结(6.1 节实测)。先查 GET /api/v2/settings 的 editabilityState 确认哪个类型只读,再决定「改 YAML 后重启」或「移除 YAML 段后重启改走 API」。读操作(GET)不受冻结影响。
Q3:创建监控器返回 400?
看响应体点名的字段:缺必填项(如 url)报 Invalid JSON: ... missing (therefore NULL) value for creator parameter url;状态页的 monitors 写成数字 id 报 Invalid monitor ID format: 2. Expected format is 'type:name'。导入 YAML 的 400 会精确到字段名与行号(10.2 节实测),照报错补齐即可。
Q4:为什么新建监控器的 uptimeStatus 是 null?
首轮检查还没跑。检查按 uptimeCheckInterval 调度(实测等约 75 秒后 stats 与事件就有了数据,见 6.6 节)。想立即看到数据可把间隔临时设小(最小 5 秒)。
Q5:v2 与 v3 该用哪个?
写操作与详情只在 v2;列表查询两个都有,v3 多分页/过滤/排序(第十一章)。事故列表要翻页时用 GET /api/v3/incidents?page=…&size=…。
Q6:删除监控器会影响事故历史吗?
会。实测删除 Push 监控器后,其 ONGOING 事故随之消失(再查返回 There is no PUSH incident with event ID: …)。要保留历史就别删监控器,改为 enabled: false 暂停。
Q7:API Key 忘了或泄露怎么办?
换一把新 Key(改部署层的 ADMIN_API_KEY 值并按部署形态重建服务)即可,旧 Key 立即失效。Key 只用于 REST API;MCP 端点用独立的 ADMIN_MCP_API_KEY,互不影响(见《KuvaszUptime 4.6.0 配置参数详解》5.1 节)。
十三、参考链接
- 官方 OpenAPI 规范(本篇端点清单出处):https://kuvasz-uptime.dev/api-docs/kuvasz-latest.yml
- 应用内 API 文档界面:
http://<服务器IP>:8141/api-docs - 官网与文档站:https://kuvasz-uptime.dev
- 官方 Changelog(4.6.0 发布记录):https://kuvasz-uptime.dev/changelog/
- 站内系列:《KuvaszUptime 介绍与选型指南》、《KuvaszUptime 4.6.0 Docker Compose 部署指南》、《KuvaszUptime 4.6.0 配置参数详解》