KuvaszUptime 4.6.0 REST API 实战指南

KuvaszUptime 4.6.0 REST API 实测手册:X-API-KEY 与 Bearer 双认证、v2/v3 端点布局,六类监控器 CRUD、心跳上报、事故与备注、状态页、维护窗口、YAML 导入导出与分页过滤约定,全部请求响应 JSON 实测回显,附 401/405/400 排障实录。

KuvaszUptimeKuvaszUptime自托管监控2026/11/01

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/healthGET
设置/api/v2/settingsGET
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}/detailsGET/POST/PATCH/DELETE
维护窗口/api/v2/maintenance-windows、/{maintenanceWindowId}GET/POST/PATCH/DELETE
集成/api/v2/integrations、/api/v2/integrations/{integrationId}/testGET/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 节)。

十三、参考链接