diff --git a/.agents/skills/translate-zh-to-en/glossary.md b/.agents/skills/translate-zh-to-en/glossary.md index 46525e1b..347dc3b2 100644 --- a/.agents/skills/translate-zh-to-en/glossary.md +++ b/.agents/skills/translate-zh-to-en/glossary.md @@ -200,4 +200,3 @@ Translatable companions (do NOT belong in DNT — translate to Chinese): | English | Chinese | |---------|---------| -| Customize | 自定义 | diff --git a/.claude/skills/translate-zh-to-en/glossary.md b/.claude/skills/translate-zh-to-en/glossary.md index 46525e1b..c1926f0b 100644 --- a/.claude/skills/translate-zh-to-en/glossary.md +++ b/.claude/skills/translate-zh-to-en/glossary.md @@ -121,6 +121,7 @@ Chinese-English terminology mapping. Maintain consistency during translation. | 解决办法 | resolution | | 推送地址 | push URL | | 跳转链接 | jump link | +| 产物 | Artifact / Artifacts | ## Actions @@ -188,7 +189,6 @@ a single half-width space on either side (e.g., `管理你的 Routines`, not | Knowledge Pack | A curated knowledge bundle attached to an Agent | | Tool call | A single tool invocation inside an Agent turn | | Slash command | UI slash-prefixed command (e.g., `/help`) | -| Artifact | Output produced by an Agent (file, doc, image) | | Reasoning | The reasoning / chain-of-thought block of a model response | | Connector | Integration with an external system (Slack, GitHub, etc.) | | Environment | Execution environment for runners (env vars, credentials) | @@ -200,4 +200,45 @@ Translatable companions (do NOT belong in DNT — translate to Chinese): | English | Chinese | |---------|---------| -| Customize | 自定义 | +| Artifact / Artifacts | 产物 | + +## Intentional Variants (per-context wording) + +These Chinese terms intentionally map to more than one English wording depending +on UI context. Every listed variant is correct — do not "unify" them. +Translators: pick the variant whose context matches. + +| Chinese | Variants (context) | +|---------|--------------------| +| 全屏 | Enter fullscreen (verb tooltip; pairs with "Exit fullscreen") / Fullscreen (compact label) | +| 来源 | Referrer (RUM view-referrer tag) / Source (generic origin) | +| 异常 | Error (metric label) / Issue (RUM Error Tracking entity, Datadog convention) | +| 状态 | Status (issue/alert status) / State (technical thread-dump state) | +| 成功 | Succeeded (run-status filter) / OK (compact badge) | +| 对话 | Chat (singular) / Chats (section header, plural) | +| 环境 | Environment (field label) / Environments (nav or page title, plural) | +| 知识库 | Knowledge Pack (singular) / Knowledge Packs (page title, plural) | +| 产物 | Artifact (singular) / Artifacts (plural) | +| 文档 | Document (artifact kind) / Documentation (docs link) | +| 邮件 | Email (channel label, pairs with "SMS") / Email us (CTA, pairs with "Call us") | +| 我的 | Personal (user menu) / My teams (team selector) | +| 团队 | Team (singular tag after a team name) / Teams (multi-select or group labels) | +| 关闭 | Close (button or rule action) / Closed (timeline event) / Dismiss (banner) | +| 天 | Day (picker label) / days (count unit) / d (compact) | +| 小时 | Hour (picker label) / hour(s) (form or count) / h (compact) | +| 条 | items (generic count) / alerts (alert count) | +| 行动项 | action (field label) / Actions (title) | +| 计划维护 | schedule maintenance (verb) / scheduled (adjective) | +| 订阅规则 | singular / plural by count context | +| 协作空间 | Channel (standalone label) / channels (plural base) | + +Plural-pair convention (zh-as-key frontends): a count-bearing Chinese key may +have English `_one` / `_other` splits (e.g. "Ran {{count}} search" / "Ran +{{count}} searches"). These pairs are intentional — never merge them into one +English value. The zh locale needs only the base key (Chinese has no plural +inflection); do not add `_one` / `_other` entries to zh locale files. + +Scope note: the "Incident Status" table above (待处理 → triggered, etc.) applies +to the incident console only. RUM dashboards follow Datadog-style triage wording +(For Review / Reviewed / Occurred At) — do not rewrite RUM strings to match that +table. diff --git a/.github/workflows/openapi-lint.yml b/.github/workflows/openapi-lint.yml new file mode 100644 index 00000000..b8d5d55b --- /dev/null +++ b/.github/workflows/openapi-lint.yml @@ -0,0 +1,28 @@ +name: Lint OpenAPI specs + +# Quality gate for the public API reference. Fails on undocumented schema +# properties, epoch time fields without Unix/timestamp wording, string enums +# whose values are not explained in the description, and operations without +# request/response examples. See scripts/lint_openapi.py for the rules. + +on: + pull_request: + paths: + - 'api-reference/*.json' + - 'scripts/lint_openapi.py' + - '.github/workflows/openapi-lint.yml' + push: + branches: [main] + paths: + - 'api-reference/*.json' + - 'scripts/lint_openapi.py' + - '.github/workflows/openapi-lint.yml' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v5 + - name: Lint specs + run: python3 scripts/lint_openapi.py diff --git a/README.md b/README.md index 98129f10..4c6e9e3e 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ English | [中文](https://github.com/flashcatcloud/flashduty-docs/blob/main/README_zh.md) [![Mintlify](https://img.shields.io/badge/Built_with-Mintlify-8B5CF6?style=flat-square)](https://mintlify.com/) -[![Docs](https://img.shields.io/badge/Live-docs.flashcat.cloud-blue?style=flat-square)](https://docs.flashcat.cloud) +[![Docs](https://img.shields.io/badge/Live-docs.flashduty.com-blue?style=flat-square)](https://docs.flashduty.com) [![License: MIT](https://img.shields.io/badge/License-MIT-green?style=flat-square)](LICENSE) Official documentation for [Flashduty](https://flashcat.cloud/), bilingual (Chinese & English), built with [Mintlify](https://mintlify.com/). Covers On-call incident management, RUM real user monitoring, and Monitors alert rules — **390+** pages in total. @@ -131,7 +131,7 @@ Full glossary: [`glossary.md`](glossary.md) | Resource | Link | |----------|------| -| Flashduty Docs | [docs.flashcat.cloud](https://docs.flashcat.cloud) | +| Flashduty Docs | [docs.flashduty.com](https://docs.flashduty.com) | | Flashduty Console | [console.flashcat.cloud](https://console.flashcat.cloud/) | | Flashduty Website | [flashcat.cloud](https://flashcat.cloud/) | | MCP Server | [flashduty-mcp-server](https://github.com/flashcatcloud/flashduty-mcp-server) | diff --git a/README_zh.md b/README_zh.md index bee3f30e..72d7b50e 100644 --- a/README_zh.md +++ b/README_zh.md @@ -3,7 +3,7 @@ [English](https://github.com/flashcatcloud/flashduty-docs/blob/main/README.md) | 中文 [![Mintlify](https://img.shields.io/badge/Built_with-Mintlify-8B5CF6?style=flat-square)](https://mintlify.com/) -[![Docs](https://img.shields.io/badge/Live-docs.flashcat.cloud-blue?style=flat-square)](https://docs.flashcat.cloud) +[![Docs](https://img.shields.io/badge/Live-docs.flashduty.com-blue?style=flat-square)](https://docs.flashduty.com) [![License: MIT](https://img.shields.io/badge/License-MIT-green?style=flat-square)](LICENSE) [Flashduty](https://flashcat.cloud/) 官方文档站,中英双语,基于 [Mintlify](https://mintlify.com/) 构建。覆盖 On-call 故障管理、RUM 真实用户监控、Monitors 告警规则三大产品模块,共 **390+** 页文档。 @@ -131,7 +131,7 @@ flashduty-docs/ | 资源 | 链接 | |------|------| -| Flashduty 文档站 | [docs.flashcat.cloud](https://docs.flashcat.cloud) | +| Flashduty 文档站 | [docs.flashduty.com](https://docs.flashduty.com) | | Flashduty 控制台 | [console.flashcat.cloud](https://console.flashcat.cloud/) | | Flashduty 官网 | [flashcat.cloud](https://flashcat.cloud/) | | MCP Server | [flashduty-mcp-server](https://github.com/flashcatcloud/flashduty-mcp-server) | diff --git a/api-reference/monitors.openapi.en.json b/api-reference/monitors.openapi.en.json index 8a1fbb71..34ae65cd 100644 --- a/api-reference/monitors.openapi.en.json +++ b/api-reference/monitors.openapi.en.json @@ -36,6 +36,10 @@ { "name": "Monitors/Monitor utilities", "description": "Monitors service activation and data preview utilities." + }, + { + "name": "Monitors/Service map", + "description": "Query network-observed service topology, dependency summaries, and ServiceMap collection status across hosts." } ], "paths": { @@ -201,7 +205,7 @@ "Monitors/Data sources" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Manage** (`monit`) |\n\n## Usage\n\n- `type_ident` must be one of: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `victorialogs`.\n- `edge_cluster_name` specifies which Monitors edge cluster evaluates rules using this datasource.\n- For `elasticsearch`, set `payload.elasticsearch.deployment` to `cloud` or `self-managed`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Manage** (`monit`) |\n\n## Usage\n\n- `type_ident` must be one of: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`.\n- `edge_cluster_name` specifies which Monitors edge cluster evaluates rules using this datasource.\n- For `elasticsearch`, set `payload.elasticsearch.deployment` to `cloud` or `self-managed`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.\n\n## Credential fields\n\nThe `info` / `create` / `update` responses include the `payload` configuration exactly as stored — `password`, `basic_auth_password`, `api_key`, `service_token`, `access_key_secret`, `tls_key`, `tls_key_pwd` and similar fields are returned as-is, not masked. The one exception is `payload.tencent_cls.secret_key`, which is always masked to an empty string (an `${env:...}` reference is returned verbatim). Treat these responses as sensitive: avoid logging them or forwarding them to third parties.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-create", "metadata": { "sidebarTitle": "Create datasource" @@ -287,7 +291,7 @@ "Monitors/Data sources" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Manage** (`monit`) |\n\n## Usage\n\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Manage** (`monit`) |\n\n## Usage\n\n- Every call is recorded in the account audit log. Don't put secrets in request fields.\n\n## Credential fields\n\nThe `info` / `create` / `update` responses include the `payload` configuration exactly as stored — `password`, `basic_auth_password`, `api_key`, `service_token`, `access_key_secret`, `tls_key`, `tls_key_pwd` and similar fields are returned as-is, not masked. The one exception is `payload.tencent_cls.secret_key`, which is always masked to an empty string (an `${env:...}` reference is returned verbatim). Treat these responses as sensitive: avoid logging them or forwarding them to third parties.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-update", "metadata": { "sidebarTitle": "Update datasource" @@ -374,7 +378,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- Rules whose names already exist in the destination folder are skipped. Inspect each result's `message` to identify conflicts.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-write-move", "metadata": { "sidebarTitle": "Move alert rules to folder" @@ -598,7 +602,7 @@ "post": { "operationId": "monit-datasource-write-delete", "summary": "Delete datasource", - "description": "Delete a data source by ID. Alert rules referencing this datasource must be updated or deleted first.", + "description": "Delete a data source by ID. Alert rules referencing this datasource are not blocked: the datasource is removed from their monitoring scope and their open alerts on it are closed automatically.", "tags": [ "Monitors/Data sources" ], @@ -774,10 +778,30 @@ }, "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": [ - "project-a", - "project-b" - ] + "data": { + "projects": [ + { + "projectName": "project-a", + "description": "Production logs", + "status": "Normal", + "owner": "", + "region": "cn-shanghai", + "createTime": "1710000000", + "lastModifyTime": "1712000000" + }, + { + "projectName": "project-b", + "description": "Staging logs", + "status": "Normal", + "owner": "", + "region": "cn-shanghai", + "createTime": "1710000000", + "lastModifyTime": "1712000000" + } + ], + "count": 2, + "total": 2 + } } } } @@ -813,83 +837,6 @@ } } }, - "/monit/rule/status": { - "post": { - "operationId": "monit-rule-write-status", - "summary": "Get rule trigger status under folder", - "description": "Return the rule trigger summary for all rules under a folder node and its descendants.", - "tags": [ - "Monitors/Alert rules" - ], - "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- Set `folder_id` to `0` to get summary across all folders.\n- If the folder contains too many rules, computation is skipped for self-protection.", - "href": "/en/api-reference/monitors/alert-rules/monit-rule-write-status", - "metadata": { - "sidebarTitle": "Get rule trigger status under folder" - } - }, - "responses": { - "200": { - "description": "Success", - "content": { - "application/json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/SuccessEnvelope" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/components/schemas/RuleStatusResponse" - } - } - } - ] - }, - "example": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": [ - { - "folder_id": 100, - "folder_name": "Production", - "rule_total": 10, - "triggered_rule_count": 2 - } - ] - } - } - } - }, - "400": { - "$ref": "#/components/responses/BadRequest" - }, - "401": { - "$ref": "#/components/responses/Unauthorized" - }, - "429": { - "$ref": "#/components/responses/TooManyRequests" - }, - "500": { - "$ref": "#/components/responses/ServerError" - } - }, - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RuleFolderIDRequest" - }, - "example": { - "folder_id": 100 - } - } - } - } - } - }, "/monit/rule/export": { "post": { "operationId": "monit-rule-read-export", @@ -899,7 +846,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **10 requests/minute**; **1 requests/second** per account |\n| Permissions | **Alerting Rules Read** (`monit`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/day**; **200 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Read** (`monit`) |", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-export", "metadata": { "sidebarTitle": "Export alert rules" @@ -935,7 +882,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *" + "cron_pattern": "0 * * * * *" } ] } @@ -1052,12 +999,12 @@ "post": { "operationId": "monit-datasource-read-info", "summary": "Get datasource detail", - "description": "Retrieve full details of a single data source by its ID, including the `payload` configuration.", + "description": "Retrieve full details of a single data source by its ID, including the `payload` configuration with its configured connection and authentication settings; treat the response as sensitive and avoid logging or forwarding it.", "tags": [ "Monitors/Data sources" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Credential fields\n\nThe `info` / `create` / `update` responses include the `payload` configuration exactly as stored — `password`, `basic_auth_password`, `api_key`, `service_token`, `access_key_secret`, `tls_key`, `tls_key_pwd` and similar fields are returned as-is, not masked. The one exception is `payload.tencent_cls.secret_key`, which is always masked to an empty string (an `${env:...}` reference is returned verbatim). Treat these responses as sensitive: avoid logging them or forwarding them to third parties.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-info", "metadata": { "sidebarTitle": "Get datasource detail" @@ -1262,7 +1209,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "channel_ids": [ 20001 ] @@ -1454,7 +1401,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `id` is required. All other fields follow the same rules as `POST /monit/rule/create`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `id` is required. All other fields follow the same rules as `POST /monit/rule/create`.\n- The name must remain unique within its folder; a duplicate returns `InvalidParameter`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-write-update", "metadata": { "sidebarTitle": "Update alert rule" @@ -1519,7 +1466,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "rule_configs": { "queries": [ { @@ -1610,7 +1557,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "rule_configs": { "queries": [ { @@ -1635,7 +1582,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `name`, `ds_type`, `cron_pattern`, and `rule_configs.queries` are required.\n- Either `ds_list` (supports wildcards) or `ds_ids` must be non-empty.\n- `cron_pattern` uses standard 5-field cron syntax.\n- `channel_ids` can be empty; alerts will then route through the global integration.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `name`, `ds_type`, `cron_pattern`, and `rule_configs.queries` are required.\n- Either `ds_list` (supports wildcards) or `ds_ids` must be non-empty.\n- `cron_pattern` uses standard 5-field cron syntax.\n- `channel_ids` can be empty; alerts will then route through the global integration.\n- `name` must be unique within `folder_id`; a duplicate returns `InvalidParameter`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-write-create", "metadata": { "sidebarTitle": "Create alert rule" @@ -1702,7 +1649,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "channel_ids": [ 20001 ], @@ -2002,7 +1949,9 @@ "ds_type": "prometheus", "enabled": true, "triggered": true, - "created_at": 1710000000 + "created_at": 1710000000, + "active_alert_count": 2, + "runtime_state": "normal" } ] } @@ -2245,7 +2194,8 @@ "note": "Production Prometheus", "address": "http://prometheus.example.com:9090", "edge_cluster_name": "default", - "updated_at": 1712000000 + "updated_at": 1712000000, + "payload": null } ] } @@ -2436,19 +2386,19 @@ } } }, - "/monit/query/rows": { + "/monit/query/data": { "post": { - "operationId": "monit-read-query-rows", - "summary": "Query data source rows", - "description": "Run a synchronous ad-hoc query against a configured data source and get back its raw rows. Used by Flashduty AI SRE and by UI preview. The request is forwarded over WebSocket to monit-edge, which executes the query against the underlying source (Prometheus / Loki / VictoriaLogs / SLS / MySQL / Postgres / Oracle / ClickHouse / Elasticsearch).", + "operationId": "monit-read-query-data", + "summary": "Query structured data", + "description": "Run a synchronous ad-hoc query against a configured data source and return a stable `query_result.v1` result whose natural shape is frames, records, or samples. This public API requires monit-edge v0.65.0 or later.", "tags": [ "Monitors/Diagnostics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- The request is forwarded to `monit-edge` over WebSocket; the data source named by `ds_type` + `ds_name` must already exist under the calling account.\n- `account_id` in the body is optional. When supplied it must equal the authenticated account; mismatched values are rejected.\n- Two error layers: webapi-level failures use the standard error envelope, but errors raised by `monit-edge` while executing the query are returned as HTTP 200 with an `error` object in the body. Always check the response body for `error` in addition to the HTTP status.\n- monit-edge enforces a row cap; large result sets come back as `error.message = \"too many rows\"`. Narrow the time range or aggregate at the source.\n- `args` is a polymorphic `string→string` map that is forwarded verbatim. Semantics depend on `ds_type` (SLS requires `sls.project` + `sls.logstore`; Loki / VictoriaLogs raw mode requires a time range via `*.start`/`*.end` or `*.timespan.value`/`*.timespan.unit`; Prometheus and SQL sources ignore it). See the monit-webapi query-api docs for the per-source key list.", - "href": "/en/api-reference/monitors/diagnostics/monit-read-query-rows", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **5 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n| Edge requirement | Supported deployments require **monit-edge v0.65.0 or later** |\n\n## Usage\n\n- Treat **monit-edge v0.65.0** as the minimum supported Edge version for this public API. WebAPI retains migration adapters for older Edge versions: query.v2 results may still preserve frames, records, or samples, while legacy rows can expose only the information they retained. These adapters do not change the support floor; older protocols lack query.v3 cancellation and error-lifecycle semantics, and data already lost by legacy rows cannot be recovered.\n- The public response format is always `query_result.v1` and is independent of the internal Edge query protocol. Dispatch on `result.kind` (`frames`, `records`, or `samples`); do not infer the result shape from `ds_type` or the Edge version.\n- A `frames` result may contain multiple table or time-series frames. Field values are columnar and all fields in one frame have the same length.\n- A `records` result may contain nested JSON and null records. Integer literals outside JavaScript's safe integer range are returned as decimal strings.\n- A `samples` result contains label sets and instant values. A value may be a number or one of the strings `NaN`, `+Inf`, and `-Inf`.\n- The final success response is limited to 8 MiB and query results are limited to 1,000 rows. Narrow the time range, reduce fields, or aggregate at the source when a request exceeds a limit.\n- Query failures use non-2xx HTTP status codes and the standard error envelope. Do not transparently fall back to the deprecated `/monit/query/rows` endpoint.\n- Query execution may take up to 35 seconds across WebAPI forwarding and Edge execution. Configure client timeouts to at least 40 seconds and propagate cancellation when the caller abandons a query.", + "href": "/en/api-reference/monitors/diagnostics/monit-read-query-data", "metadata": { - "sidebarTitle": "Query data source rows" + "sidebarTitle": "Query structured data" } }, "requestBody": { @@ -2456,14 +2406,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/QueryRowsRequest" + "$ref": "#/components/schemas/QueryDataRequest" }, "example": { - "account_id": 10001, "ds_type": "prometheus", "ds_name": "prod-prom", - "expr": "up", - "delay_seconds": 30 + "expr": "sum by (job) (rate(http_requests_total[5m]))", + "delay_seconds": 0, + "args": {} } } } @@ -2482,7 +2432,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/QueryRowsResponse" + "$ref": "#/components/schemas/QueryDataResponse" } } } @@ -2490,18 +2440,20 @@ }, "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": [ - { - "fields": { - "__name__": "up", - "instance": "10.0.0.1:9100", - "job": "node" - }, - "values": { - "__value__": 1 - } + "data": { + "format": "query_result.v1", + "result": { + "kind": "samples", + "samples": [ + { + "labels": { + "job": "api" + }, + "value": 1.25 + } + ] } - ] + } } } } @@ -2512,11 +2464,47 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, + "413": { + "description": "The request or final response exceeds its size limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, + "499": { + "description": "The client canceled the query.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, "500": { "$ref": "#/components/responses/ServerError" + }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, + "504": { + "description": "The query timed out.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } } } } @@ -2530,7 +2518,7 @@ "Monitors/Diagnostics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- This is a diagnostic / RCA endpoint, not a raw data query — pair it with `/monit/query/rows` when you need detailed rows.\n- `operation` defaults from `ds_type`: `loki` / `victorialogs` → `log_patterns`, `prometheus` → `metric_trends`. Other sources must pass `operation` explicitly.\n- `methods` selects the analyses to run; when omitted, `log_patterns` defaults to `pattern_snapshot + pattern_compare(previous_window)` and `metric_trends` defaults to `single_window_shape + window_compare(previous_window)`.\n- `time_range` is in Unix seconds; missing or invalid values default to the last 15 minutes; a window wider than 6 hours is rejected.\n- The request is forwarded over WebSocket to `monit-edge`. Long-running: the request may take up to ~30 s on the edge side plus webapi overhead. Set client timeouts to **at least 35 s**.\n- `options.*` are upper-bounded by edge (`max_logs_scanned` ≤ 50 000, `max_patterns` ≤ 50, `examples_per_pattern` ≤ 3, `step_seconds` ∈ [15, 300], `max_series` ≤ 200, `topk` ≤ 50, `timeout_seconds` ≤ 30).\n- Two error layers as with `/monit/query/rows`: edge-level execution errors come back as HTTP 200 with an `error` object in the body — check both layers.\n- Log examples are basic-redacted before being returned; expect `warnings: [\"examples redacted\"]`. Do not treat them as raw logs.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- This is a diagnostic / RCA endpoint, not a raw data query — pair it with `/monit/query/data` when you need the underlying data.\n- Only three `ds_type` and `operation` pairs are supported: `loki` / `victorialogs` → `log_patterns`, and `prometheus` → `metric_trends`. Every other datasource is rejected, even when `operation` is explicit.\n- `methods` selects the analyses to run; when omitted, `log_patterns` defaults to `pattern_snapshot + pattern_compare(previous_window)` and `metric_trends` defaults to `single_window_shape + window_compare(previous_window)`.\n- `time_range` is in Unix seconds; missing or invalid values default to the last 15 minutes; a window wider than 6 hours is rejected.\n- The request is forwarded over WebSocket to `monit-edge`. Long-running: the request may take up to ~30 s on the edge side plus webapi overhead. Set client timeouts to **at least 35 s**.\n- `options.*` are upper-bounded by edge (`max_logs_scanned` ≤ 50 000, `max_patterns` ≤ 50, `examples_per_pattern` ≤ 3, `step_seconds` ∈ [15, 300], `max_series` ≤ 200, `topk` ≤ 50, `timeout_seconds` ≤ 30).\n- The success body is a raw `{\"data\": ...}` object WITHOUT the usual `request_id` wrapper field (raw passthrough from the edge).\n- Two error layers: request-level failures return a non-200 status with the standard `error` envelope, while edge-level execution errors come back as HTTP 200 with an `error` object in the body — check both.\n- Log examples are basic-redacted before being returned; expect `warnings: [\"examples redacted\"]`. Do not treat them as raw logs.", "href": "/en/api-reference/monitors/diagnostics/monit-read-query-diagnose", "metadata": { "sidebarTitle": "Diagnose data source" @@ -2597,59 +2585,89 @@ "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { + "schema_version": "2", "operation": "log_patterns", - "ds_type": "victorialogs", - "ds_name": "vmlogs-read", - "query": "_stream:{status='500'}", + "ds_type": "loki", + "ds_name": "prod-loki", + "query": "{service=\"checkout\"}", "window": { - "start": 1776847544, - "end": 1776849344 + "start": "2026-07-14T06:00:00Z", + "end": "2026-07-14T07:00:00Z" + }, + "data_handling": { + "log_redaction_applied": true, + "log_redaction_coverage": "best_effort", + "untrusted_data_fields": [ + "pattern_template", + "current_window.sources[].value", + "redacted_log_examples[]" + ] }, "results": [ { - "method": "pattern_snapshot", + "method": "pattern_compare", + "baseline": "previous_window", "window": { - "start": 1776847544, - "end": 1776849344 + "start": "2026-07-14T06:00:00Z", + "end": "2026-07-14T07:00:00Z" + }, + "baseline_window": { + "start": "2026-07-14T05:00:00Z", + "end": "2026-07-14T06:00:00Z" }, "summary": { - "logs_scanned": 405, - "baseline_logs_scanned": 0, - "current_truncated": false, - "baseline_truncated": false, - "patterns_total": 2, - "returned_patterns": 2, - "new_patterns": 0, - "surging_patterns": 0, - "surging_threshold": { - "change_ratio_min": 3, - "count_min": 5 - } + "current_sample": { + "logs_scanned": 10000, + "patterns_aggregated": 18, + "logs_not_aggregated_due_to_cluster_limit": 0, + "pattern_matching_limited": false, + "truncated": false + }, + "baseline_sample": { + "logs_scanned": 8000, + "patterns_aggregated": 20, + "logs_not_aggregated_due_to_cluster_limit": 0, + "pattern_matching_limited": false, + "truncated": false + }, + "patterns_aggregated_only_in_baseline_sample": 2, + "aggregated_pattern_evidence_total": 20, + "pattern_evidence_returned": 1, + "pattern_evidence_truncated_by_max_patterns": true, + "evidence_summary": "1 of 20 pattern evidence items are returned." }, - "patterns": [ + "pattern_evidence": [ { - "pattern_hash": "239fa5da", - "template": "POST /api/v/orders/ HTTP/", - "count": 213, - "first_seen": 1776847562, - "last_seen": 1776849336, - "severity": "unknown", - "approximate": false, - "sources": [ - { - "field": "pod", - "value": "order-api-7f69d8d9b6-m4x9n", - "count": 130 + "pattern_id": "8f1496a85df86ca1", + "pattern_template": "checkout request <*> failed", + "comparison_status": "comparable", + "current_window": { + "count": 12, + "share_of_scanned_logs": 0.0012, + "first_seen": "2026-07-14T06:03:00Z", + "last_seen": "2026-07-14T06:58:00Z", + "observed_severity_counts": { + "error": 12 } + }, + "baseline_window": { + "count": 2, + "share_of_scanned_logs": 0.00025, + "first_seen": "2026-07-14T05:11:00Z", + "last_seen": "2026-07-14T05:44:00Z", + "observed_severity_counts": { + "error": 2 + } + }, + "observations": [ + "The current-sample count was 12 and the baseline-sample count was 2." ], - "examples": [ - "POST /api/v/orders/ HTTP/" + "redacted_log_examples": [ + "checkout request failed" ] } ], - "warnings": [ - "examples redacted" - ] + "warnings": [] } ] } @@ -2681,7 +2699,7 @@ "Monitors/Diagnostics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- Use `target_locator` to identify the target; `target_kind` is optional and is auto-inferred when omitted. Built-in target kinds are `host` and `mysql`.\n- If multiple kinds match the same locator, the response is HTTP 200 with `data.error.code = \"ambiguous_target_kind\"` and a `target_kinds` list — retry with an explicit `target_kind`.\n- The catalog is a *candidate capability* view, not an execution guarantee. The target Agent may go offline between catalog and invoke, or local Agent policy may block individual tools at invoke time.\n- Set `include_output_shape: true` to additionally receive each tool's `output_shape`. Default is `false` to keep the response small for LLM consumption.\n- Business errors (`target_unavailable`, `unknown_toolset_hash`, `ambiguous_target_kind`) come back as HTTP 200 with a non-null `data.error`. Only protocol / auth / internal errors use the standard error envelope.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- Use `target_locator` to identify the target; `target_kind` is optional and is inferred from current target routing when omitted.\n- If multiple kinds match the same locator, the response is HTTP 200 with `data.error.code = \"ambiguous_target_kind\"` and a `target_kinds` list — retry with an explicit `target_kind`.\n- The catalog is a candidate capability view, not an execution guarantee. The target Agent may go offline between catalog and invoke, or local Agent policy may block individual tools at invoke time.\n- Each tool entry exposes only `name`, `target_kind`, `description`, and `input_schema`. It does not expose tool versions, output contracts, catalog revisions, or execution limits.\n- Business errors (`target_unavailable`, `timeout`, `forward_failed`, `invalid_tool_result`, `ambiguous_target_kind`) return HTTP 200 with `data.error` present and `data.tools = []`. Only protocol, authentication, and internal errors use the standard error envelope.\n- The response uses **sparse fields**: on success `error` is omitted rather than sent as `null`, and `target` is omitted when the locator could not be uniquely resolved. `tools` is always present.", "href": "/en/api-reference/monitors/diagnostics/monit-read-tools-catalog", "metadata": { "sidebarTitle": "List target tool catalog" @@ -2696,8 +2714,7 @@ }, "example": { "account_id": 10001, - "target_locator": "web-01", - "include_output_shape": true + "target_locator": "web-01" } } } @@ -2733,34 +2750,35 @@ { "name": "os.overview", "target_kind": "host", - "description": "Returns a bounded overview of host health (CPU, memory, disk, network, top processes).", + "description": "Returns a bounded overview of host health: CPU usage and load, memory and swap utilisation, disk and network counters, and top processes.", "input_schema": { "type": "object", "additionalProperties": false, "properties": {} - }, - "output_shape": { + } + }, + { + "name": "net.tcp_ping", + "target_kind": "host", + "description": "Checks TCP reachability of a host:port from the target, reporting connect latency.", + "input_schema": { "type": "object", + "additionalProperties": false, "required": [ - "data", - "summary", - "truncated" + "host", + "port" ], "properties": { - "data": { - "type": "object" - }, - "summary": { + "host": { "type": "string" }, - "truncated": { - "type": "object" + "port": { + "type": "integer" } } } } - ], - "error": null + ] } } } @@ -2790,7 +2808,7 @@ "Monitors/Diagnostics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- Up to **8** tools per call (`MaxToolsPerInvoke`); larger batches must be split client-side. The 8-tool cap aligns with the per-target agent concurrency.\n- Tools execute in parallel on the agent; webapi returns `results[]` aligned with the request `tools[]` order.\n- Long-running: set client timeouts to **at least 35 s**. The endpoint is intended for AI-SRE / human-RCA flows, not interactive UI.\n- Request-level errors (`target_unavailable`, `ambiguous_target_kind`, `unknown_toolset_hash`, `forward_failed`) appear as HTTP 200 with `data.error` set and `data.results = []`.\n- Per-tool failures appear as HTTP 200 with `data.error = null` and `results[i].error` populated — always check **all three** layers (outer envelope `error`, `data.error`, then each `results[i].error`).\n- Each result carries two latency fields: `agent_elapsed_ms` (agent-self-reported, excludes network) and `e2e_elapsed_ms` (webapi-observed end-to-end). A large gap between them indicates network / edge slowness rather than slow tool execution.\n- Construct `tools[].params` against the `input_schema` returned by `/monit/tools/catalog`. For no-arg tools always pass `params: {}` explicitly.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **600 requests/minute**; **10 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n\n## Usage\n\n- Up to **8** tools per call (`MaxToolsPerInvoke`); larger batches must be split client-side. The 8-tool cap aligns with the per-target agent concurrency.\n- Tools execute in parallel on the agent; webapi returns `results[]` aligned with the request `tools[]` order.\n- Long-running: set client timeouts to **at least 35 s**. The endpoint is intended for AI-SRE / human-RCA flows, not interactive UI.\n- Request-level errors (`target_unavailable`, `ambiguous_target_kind`, `forward_failed`) appear as HTTP 200 with `data.error` set and `data.results = []`.\n- Per-tool failures appear as HTTP 200 with `data.error` absent and `results[i].error` populated — always check **all three** layers (outer envelope `error`, `data.error`, then each `results[i].error`).\n- The response uses **sparse fields**: absent means empty. On success `error` is omitted entirely rather than sent as `null`; on failure `data`, `summary` and `truncated` are omitted. Do not key logic off placeholder `null` fields, and do not expect `target` when the locator could not be uniquely resolved.\n- `results[i].data` is the tool payload with the monit-agent result envelope **already unwrapped** — there is no nested `data.data`. The one-line distillation is `results[i].summary`, and `results[i].truncated` (carrying a `reason`) appears only when the result was genuinely truncated.\n- `results[i].params` echoes the params webapi received for that tool, so batched calls stay correlatable even when an individual tool fails.\n- Construct `tools[].params` against the `input_schema` returned by `/monit/tools/catalog`. For no-arg tools always pass `params: {}` explicitly.", "href": "/en/api-reference/monitors/diagnostics/monit-read-tools-invoke", "metadata": { "sidebarTitle": "Invoke target tools" @@ -2853,35 +2871,41 @@ "results": [ { "tool": "os.overview", - "tool_version": "0.5.0", + "params": {}, + "tool_version": "0.6.0", "data": { - "data": { - "sample_interval_sec": 3, - "degraded": false, - "degradation_reasons": [] + "sample_interval_sec": 0.5, + "cpu": { + "cores": 4, + "usage_pct": 32.66, + "user_pct": 28.14, + "system_pct": 3.52, + "iowait_pct": 1.01, + "idle_pct": 67.34 }, - "summary": "os.overview ...", - "truncated": { - "truncated": false + "load": { + "load1": 1.79, + "load5": 1.83, + "load15": 1.67, + "runnable_procs": 7, + "total_procs": 1036 } }, - "error": null, - "agent_elapsed_ms": 3120, - "e2e_elapsed_ms": 3188 + "summary": "os.overview cpu=32.66% mem=74.46% swap=not_configured oom_kill_since_boot=2 load1=1.79" }, { "tool": "net.tcp_ping", - "tool_version": "0.5.0", - "data": null, - "error": { - "code": "target_unreachable", - "message": "dial tcp 10.0.0.10:3306: i/o timeout" + "params": { + "host": "10.255.255.1", + "port": 3306 }, - "agent_elapsed_ms": 0, - "e2e_elapsed_ms": 2008 + "tool_version": "0.1.0", + "error": { + "code": "timeout", + "message": "tool \"net.tcp_ping\" exceeded 8000ms" + } } - ], - "error": null + ] } } } @@ -2986,19 +3010,19 @@ } } }, - "/monit/preview/sync": { + "/monit/servicemap/status": { "post": { - "operationId": "monit-preview-sync", - "summary": "Preview datasource query", - "description": "Execute a synchronous datasource query and return the raw result. Used to preview alert rule expressions before saving.", + "operationId": "monit-servicemap-read-status", + "summary": "Get service map status", + "description": "Return ServiceMap collection status for one or more hosts, or a bounded fleet sample.", "tags": [ - "Monitors/Monitor utilities" + "Monitors/Service map" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **60 requests/minute**; **10 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- `ds_type` must match the datasource type (e.g. `prometheus`, `loki`).\n- `ds_name` is the display name of the datasource as configured in the account.\n- `delay_seconds` shifts the query window backward by the specified number of seconds, useful for accommodating data ingestion latency.\n- The response body is the raw JSON returned by the datasource — its schema varies by datasource type.", - "href": "/en/api-reference/monitors/monitor-utilities/monit-preview-sync", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **5 requests/second** per account |\n| Permissions | **Targets Read** (`monit`) |\n\n## Usage\n\n- ServiceMap is an optional subsystem: a deployment without `redis.servicemap` configured returns `ServiceUnavailable`.\n- Exactly one selection mode is used per call: explicit `host_id`/`host_ids`, or `fleet=true`; combining `fleet=true` with either host field is rejected.\n- Unlike `POST /monit/servicemap/topology` and `POST /monit/servicemap/summary`, an unresolvable host does not fail the whole request — it is reported per item via `items[].error_code`.\n- `limit` (default 100, max 200) bounds the number of explicit hosts accepted, and in `fleet` mode, the number of candidate hosts sampled.", + "href": "/en/api-reference/monitors/service-map/monit-servicemap-read-status", "metadata": { - "sidebarTitle": "Preview datasource query" + "sidebarTitle": "Get service map status" } }, "responses": { @@ -3015,7 +3039,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/PreviewSyncResponse" + "$ref": "#/components/schemas/ServiceMapStatusResponse" } } } @@ -3024,11 +3048,59 @@ "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { - "status": "success", - "data": { - "resultType": "vector", - "result": [] - } + "fleet": false, + "items": [ + { + "host_id": "host_0123456789abcdef0123456789abcdef", + "network_scope_id": "ns_0123456789abcdef0123456789abcdef", + "status": "active", + "authoritative": true, + "graph_available": true, + "capability": { + "present": true, + "enabled": true, + "status": "running", + "host_id": "host_0123456789abcdef0123456789abcdef", + "capture_mode": "ebpf", + "report_interval_ms": 60000, + "snapshot_ready": true + }, + "freshness": { + "status": "fresh", + "newest_received_at_ms": 1784635557272, + "oldest_received_at_ms": 1784635557272, + "max_age_ms": 1200 + }, + "coverage": { + "degraded": false, + "truncated": false, + "network_inventory_status": "complete", + "kubernetes_enrichment_status": "unavailable" + }, + "observed_at_ms": 1784635556072, + "received_at_ms": 1784635557272, + "report_interval_ms": 60000, + "node_count": 12, + "edge_count": 8 + } + ], + "coverage": { + "requested": 1, + "succeeded": 1, + "failed": 0, + "truncated": false, + "states": { + "active": 1, + "degraded": 0, + "stale": 0, + "initializing": 0, + "disabled": 0, + "unsupported": 0, + "no_data": 0 + } + }, + "partial": false, + "generated_at_ms": 1784635558472 } } } @@ -3040,6 +3112,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3052,56 +3127,609 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PreviewSyncRequest" + "$ref": "#/components/schemas/ServiceMapStatusRequest" }, "example": { - "ds_type": "prometheus", - "ds_name": "Prometheus Prod", - "expr": "rate(http_requests_total[5m])", - "delay_seconds": 0 + "host_id": "host_0123456789abcdef0123456789abcdef" } } } } } - } - }, - "components": { - "securitySchemes": { - "AppKeyAuth": { - "type": "apiKey", - "in": "query", - "name": "app_key", - "description": "App key issued from the Flashduty console under Account → APP Keys. Required on every public API call. Keep it secret — it grants the same access as the owning account." - } }, - "responses": { - "BadRequest": { - "description": "Invalid request — usually a missing or malformed parameter.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "missingParameter": { - "value": { + "/monit/servicemap/topology": { + "post": { + "operationId": "monit-servicemap-read-topology", + "summary": "Get service map topology", + "description": "Return the outbound dependency graph around a host, discovered by live network observation.", + "tags": [ + "Monitors/Service map" + ], + "x-mint": { + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **20 requests/minute**; **1 request/second** per account |\n| Permissions | **Service Map Read** (`monit`) |\n\n## Usage\n\n- ServiceMap is an optional subsystem: a deployment without `redis.servicemap` configured returns `ServiceUnavailable`.\n- `at` currently only accepts `now` (or empty, which behaves identically).\n- `direction` currently only accepts `outbound` (or empty).\n- `anchor.host_id` must already be known to ServiceMap (have a current or recently retired graph); otherwise this returns `ResourceNotFound`.\n- `depth` (max 3), `max_nodes` (max 500), and `max_edges` (max 1000) bound the traversal; when a bound is hit, `truncated=true` and `truncation_reasons` explains why.\n- `unresolved_mode=summary` (vs. the default `full`) omits unresolved edges from `edges` and returns only a bounded sample in `unresolved_endpoints`.", + "href": "/en/api-reference/monitors/service-map/monit-servicemap-read-topology", + "metadata": { + "sidebarTitle": "Get service map topology" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ServiceMapTopologyResponse" + } + } + } + ] + }, + "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "InvalidParameter", - "message": "The specified parameter is not valid." + "data": { + "network_scope_id": "ns_0123456789abcdef0123456789abcdef", + "anchor_host_id": "host_0123456789abcdef0123456789abcdef", + "observed_at_ms": 1784635556072, + "freshness": { + "status": "fresh", + "newest_received_at_ms": 1784635557272, + "oldest_received_at_ms": 1784635557272, + "max_age_ms": 1200 + }, + "coverage": { + "direction": "outbound", + "hosts_loaded": 2, + "degraded_hosts": 0, + "truncated_hosts": 0, + "capture_modes": [ + "ebpf" + ], + "network_inventory_status": "complete", + "kubernetes_enrichment_status": "unavailable", + "listener_address_family_status": "complete", + "ipv6_wildcard_listener_count": 0, + "ipv6_only_known_listener_count": 0, + "ipv6_only_unknown_listener_count": 0 + }, + "truncated": false, + "nodes": [ + { + "host_id": "host_0123456789abcdef0123456789abcdef", + "id": "procw_v1_source", + "kind": "process", + "display_name": "orders.service", + "systemd_unit": "orders.service", + "first_seen": "2026-07-01T02:00:00Z", + "last_seen": "2026-07-21T18:45:56.072+08:00" + }, + { + "host_id": "host_fedcba9876543210fedcba9876543210", + "id": "procw_v1_mysql", + "kind": "process", + "display_name": "mysqld.service", + "systemd_unit": "mysqld.service", + "first_seen": "2026-07-01T02:00:00Z", + "last_seen": "2026-07-21T18:45:56.072+08:00" + } + ], + "edges": [ + { + "host_id": "host_0123456789abcdef0123456789abcdef", + "id": "edge_v1_example", + "source_entity_id": "procw_v1_source", + "source_netns_id": "netns_v1_default", + "destination": { + "ip": "203.0.113.105", + "port": 3306, + "protocol": "tcp" + }, + "evidence": "connect", + "last_seen": "2026-07-21T18:45:56.072+08:00", + "depth": 1, + "endpoint_resolution": { + "status": "resolved", + "endpoint": { + "ip": "203.0.113.105", + "port": 3306, + "protocol": "tcp" + }, + "candidates": [ + { + "host_id": "host_fedcba9876543210fedcba9876543210", + "entity_id": "procw_v1_mysql", + "netns_id": "netns_v1_default", + "listener_id": "listener_v1_mysql", + "listener_ip": "203.0.113.105", + "effective_ip": "203.0.113.105", + "protocol": "tcp", + "port": 3306, + "match_kind": "exact", + "confidence": 1.0, + "node_kind": "process", + "node_display_name": "mysqld.service", + "graph_sequence": 42, + "observed_at_ms": 1784635556072 + } + ] + } + } + ], + "unresolved_endpoints": [], + "resolution_counts": { + "resolved": 1, + "ambiguous": 0, + "unresolved": 0 + }, + "unresolved_projection": { + "mode": "full", + "total": 0, + "returned": 0, + "omitted": 0, + "by_reason": [] + } } } } } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMapTopologyRequest" + }, + "example": { + "anchor": { + "host_id": "host_0123456789abcdef0123456789abcdef" + }, + "depth": 2, + "max_nodes": 100, + "max_edges": 200, + "include_metrics": true, + "unresolved_mode": "full" + } + } } } - }, - "Unauthorized": { - "description": "Missing or invalid app_key.", - "content": { - "application/json": { - "schema": { + } + }, + "/monit/servicemap/summary": { + "post": { + "operationId": "monit-servicemap-read-summary", + "summary": "Get service map summary", + "description": "Return a bounded, AI-ready summary of a host's outbound service dependencies.", + "tags": [ + "Monitors/Service map" + ], + "x-mint": { + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **2 requests/second** per account |\n| Permissions | **Service Map Read** (`monit`) |\n\n## Usage\n\n- ServiceMap is an optional subsystem: a deployment without `redis.servicemap` configured returns `ServiceUnavailable`.\n- `anchor.host_id` must already be known to ServiceMap; otherwise this returns `ResourceNotFound`.\n- This is a fixed-size digest, not a scaled-down `POST /monit/servicemap/topology`: depth is always 1 and neighbors are capped at 12, and none of the sizing is caller-adjustable.\n- `context_ref_detail` is a pre-rendered natural-language evidence string designed for LLM prompts; the structured fields are the source of truth and this is a convenience rendering of them.\n- `graph_role=last_known_good` means the latest ingestion is unhealthy and the summary reflects the last authoritative graph rather than a live one.", + "href": "/en/api-reference/monitors/service-map/monit-servicemap-read-summary", + "metadata": { + "sidebarTitle": "Get service map summary" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ServiceMapSummaryResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "network_scope_id": "ns_0123456789abcdef0123456789abcdef", + "anchor_host_id": "host_0123456789abcdef0123456789abcdef", + "status": "active", + "authoritative": true, + "graph_role": "current", + "latest_collection_authoritative": true, + "observed_at_ms": 1784635556072, + "received_at_ms": 1784635557272, + "freshness": { + "status": "fresh", + "newest_received_at_ms": 1784635557272, + "oldest_received_at_ms": 1784635557272, + "max_age_ms": 1200 + }, + "coverage": { + "direction": "outbound", + "hosts_loaded": 2, + "degraded_hosts": 0, + "truncated_hosts": 0, + "capture_modes": [ + "ebpf" + ], + "network_inventory_status": "complete", + "kubernetes_enrichment_status": "unavailable" + }, + "truncated": false, + "resolution_counts": { + "resolved": 1, + "ambiguous": 0, + "unresolved": 0 + }, + "neighbors": [ + { + "edge_id": "edge_v1_example", + "source_entity_id": "procw_v1_source", + "source_display_name": "orders.service", + "resolution_status": "resolved", + "target_host_id": "host_fedcba9876543210fedcba9876543210", + "target_entity_id": "procw_v1_mysql", + "target_display_name": "mysqld.service", + "destination_protocol": "tcp", + "destination_ip": "203.0.113.105", + "destination_port": 3306, + "last_seen": "2026-07-21T18:45:56.072+08:00", + "active_connections": 1 + } + ], + "context_ref_detail": "ServiceMap current bounded evidence: anchor_host_id=host_0123456789abcdef0123456789abcdef; observed_at_ms=1784635556072; received_at_ms=1784635557272; latest_health_at_ms=0; status=active; freshness=fresh; graph_authoritative=true; latest_collection_authoritative=true; coverage_hosts=2; resolution_counts=resolved:1,ambiguous:0,unresolved:0; truncated=false. Observed outbound relations (relations_shown=1/1): [orders.service -> mysqld.service, resolution=resolved, last_seen=2026-07-21T18:45:56.072+08:00] Evidence rules: only resolution=resolved relations are certain; treat ambiguous/unresolved relations as leads to verify, not fact." + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMapSummaryRequest" + }, + "example": { + "anchor": { + "host_id": "host_0123456789abcdef0123456789abcdef" + } + } + } + } + } + } + }, + "/monit/servicemap/fleet": { + "post": { + "operationId": "monit-servicemap-read-fleet", + "summary": "Browse service map fleet hosts", + "description": "Browse the account's hosts with ServiceMap capability and current collection status.", + "tags": [ + "Monitors/Service map" + ], + "x-mint": { + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **2 requests/second** per account |\n| Permissions | **Targets Read** (`monit`) |\n\n## Usage\n\n- Unlike the other four ServiceMap read APIs, this endpoint degrades gracefully when the ServiceMap store is unavailable: matching still runs off inventory data, and affected items report `servicemap.error_code=status_unavailable` with `partial=true`, instead of the whole request failing.\n- `cursor` is opaque — pass back the exact value from `next_cursor`; do not construct or parse it.\n- Reaching `scan_limit` before `limit` matches are found sets `truncated=true` with `next_cursor` still populated — this is not the same as reaching the end of the account's hosts.\n- `coverage.scanned`/`matched`/`returned` describe this page's scan only, not the account's total host population.", + "href": "/en/api-reference/monitors/service-map/monit-servicemap-read-fleet", + "metadata": { + "sidebarTitle": "Browse service map fleet hosts" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ServiceMapFleetBrowseResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "items": [ + { + "host_id": "host_0123456789abcdef0123456789abcdef", + "agent_version": "v1.2.3", + "edge_cluster": "edge-a", + "servicemap": { + "enabled": true, + "status": "degraded", + "capability_status": "degraded", + "capture_mode": "ebpf", + "snapshot_ready": true, + "authoritative": true, + "graph_available": false, + "freshness_status": "fresh", + "observed_at_ms": 1784635557272, + "received_at_ms": 1784635557272, + "node_count": 46, + "edge_count": 200, + "reason_codes": [ + "snapshot_incomplete" + ] + } + }, + { + "host_id": "host_fedcba9876543210fedcba9876543210", + "agent_version": "v1.2.3", + "edge_cluster": "edge-a", + "servicemap": { + "enabled": true, + "status": "stale", + "capability_status": "running", + "capture_mode": "ebpf", + "snapshot_ready": true, + "authoritative": true, + "graph_available": true, + "freshness_status": "stale", + "observed_at_ms": 1784631957272, + "received_at_ms": 1784631957272, + "node_count": 38, + "edge_count": 152 + } + } + ], + "coverage": { + "scanned": 80, + "matched": 2, + "returned": 2, + "failed": 0, + "states": { + "active": 0, + "degraded": 1, + "stale": 1, + "initializing": 0, + "disabled": 0, + "unsupported": 0, + "no_data": 0 + } + }, + "partial": false, + "truncated": false, + "generated_at_ms": 1784635557272 + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMapFleetBrowseRequest" + }, + "example": { + "limit": 50, + "scan_limit": 1000, + "statuses": [ + "degraded", + "stale" + ], + "agent_versions": [ + "v1.2.3" + ], + "edge_clusters": [ + "edge-a" + ], + "capture_modes": [ + "ebpf" + ] + } + } + } + } + } + }, + "/monit/servicemap/fleet/summary": { + "post": { + "operationId": "monit-servicemap-read-fleet-summary", + "summary": "Get service map fleet summary", + "description": "Return an aggregate status distribution across the account's ServiceMap-capable hosts.", + "tags": [ + "Monitors/Service map" + ], + "x-mint": { + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **10 requests/minute**; **1 request/second** per account |\n| Permissions | **Targets Read** (`monit`) |\n\n## Usage\n\n- Like `POST /monit/servicemap/fleet`, this endpoint degrades gracefully when the ServiceMap store is unavailable rather than failing the whole request.\n- This is a single-request, unpaginated aggregate over up to `scan_limit` hosts (default 2000, max 5000) — it does not return per-host detail or accept a status filter.\n- Reaching `scan_limit` before scanning the whole account sets `truncated=true`; `coverage.states` reflects only the hosts actually scanned, not the account's full population.", + "href": "/en/api-reference/monitors/service-map/monit-servicemap-read-fleet-summary", + "metadata": { + "sidebarTitle": "Get service map fleet summary" + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/components/schemas/ServiceMapFleetSummaryResponse" + } + } + } + ] + }, + "example": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "data": { + "coverage": { + "scanned": 1200, + "matched": 1150, + "classified": 1149, + "failed": 1, + "states": { + "active": 1000, + "degraded": 20, + "stale": 30, + "initializing": 40, + "disabled": 25, + "unsupported": 4, + "no_data": 30 + } + }, + "scan_limit": 2000, + "partial": true, + "truncated": false, + "generated_at_ms": 1784635557272 + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "$ref": "#/components/responses/ServerError" + } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMapFleetSummaryRequest" + }, + "example": { + "scan_limit": 2000, + "agent_versions": [ + "v1.2.3" + ], + "edge_clusters": [ + "edge-a" + ], + "capture_modes": [ + "ebpf" + ] + } + } + } + } + } + } + }, + "components": { + "securitySchemes": { + "AppKeyAuth": { + "type": "apiKey", + "in": "query", + "name": "app_key", + "description": "App key issued from the Flashduty console under Account → APP Keys. Required on every public API call. Keep it secret — it grants the same access as the owning account." + } + }, + "responses": { + "BadRequest": { + "description": "Invalid request — usually a missing or malformed parameter.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "missingParameter": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "InvalidParameter", + "message": "The specified parameter is not valid." + } + } + } + } + } + } + }, + "Unauthorized": { + "description": "Missing or invalid app_key.", + "content": { + "application/json": { + "schema": { "$ref": "#/components/schemas/ErrorResponse" }, "examples": { @@ -3201,29 +3829,52 @@ } } } - } - }, - "schemas": { - "AlertRule": { - "type": "object", - "description": "Full alert rule configuration.", - "properties": { + }, + "ServiceUnavailable": { + "description": "The ServiceMap subsystem is not enabled or not reachable on this deployment. Include the request_id when reporting.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "serviceMapDisabled": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "ServiceUnavailable", + "message": "servicemap store is not initialized" + } + } + } + } + } + } + } + }, + "schemas": { + "AlertRule": { + "type": "object", + "description": "Full alert rule configuration.", + "properties": { "id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "Rule ID. Required for update; omit for create (assigned by the server)." }, "account_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "Account ID. Filled by the server from the authenticated identity; do not provide." }, "folder_id": { "type": "integer", "format": "uint64", - "description": "Folder the rule belongs to." + "description": "ID of the folder the rule belongs to. Obtainable via `POST /monit/folder/list`." }, "name": { "type": "string", - "description": "Rule name." + "description": "Rule name. Must be unique within the same folder." }, "labels": { "type": "object", @@ -3234,14 +3885,14 @@ }, "ds_type": { "type": "string", - "description": "Data source type." + "description": "Datasource type identifier; allowed values are listed by `POST /monit/rule/dstypes` (e.g. `prometheus`, `elasticsearch`)." }, "ds_list": { "type": "array", "items": { "type": "string" }, - "description": "Data source name patterns (supports wildcards)." + "description": "Data source name patterns (supports wildcards). At least one of `ds_list` / `ds_ids` must be non-empty; the two are merged to decide which datasources the rule monitors." }, "ds_ids": { "type": "array", @@ -3249,20 +3900,23 @@ "type": "integer", "format": "uint64" }, - "description": "Specific data source IDs." + "description": "Datasource IDs, merged with `ds_list` to decide which datasources the rule monitors; IDs survive datasource renames. At least one of `ds_list` and `ds_ids` must be provided." }, "enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether the rule is enabled. Updating to `false` makes the server clean up the rule's active alerts." }, "debug_log_enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether to enable debug logging; the edge emits detailed evaluation logs, useful for troubleshooting rules that do not trigger as expected." }, "rule_configs": { - "$ref": "#/components/schemas/RuleConfigs" + "$ref": "#/components/schemas/RuleConfigs", + "description": "Check configuration: query list plus trigger/recovery conditions. Structure see `RuleConfigs`." }, "cron_pattern": { "type": "string", - "description": "5-field cron schedule. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." + "description": "Schedule expression: a 6-field cron (with seconds) or an `@every 30s` interval descriptor. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." }, "timezone": { "type": "string", @@ -3270,11 +3924,27 @@ "default": "Asia/Shanghai" }, "delay_seconds": { - "type": "integer" + "type": "integer", + "description": "Seconds to shift the evaluation query window backward, compensating for data ingestion latency." }, "enabled_times": { "type": "array", - "description": "Time windows when the rule is active.", + "description": "Time windows when the rule is active. Defaults to all days from 00:00 to 23:59 when omitted or empty.", + "default": [ + { + "days": [ + 1, + 2, + 3, + 4, + 5, + 6, + 0 + ], + "stime": "00:00", + "etime": "23:59" + } + ], "items": { "type": "object", "properties": { @@ -3300,17 +3970,21 @@ "type": "object", "additionalProperties": { "type": "string" - } + }, + "description": "Annotation key-value pairs delivered with alert events; keys must not start with `$` (reserved for query fields)." }, "description_type": { "type": "string", "enum": [ "text", "markdown" - ] + ], + "default": "text", + "description": "Format for the description. Defaults to `text` when omitted or empty. `text` = plain text; `markdown` = Markdown, rendered as Markdown in alert details." }, "description": { - "type": "string" + "type": "string", + "description": "Rule description, in Markdown." }, "channel_ids": { "type": "array", @@ -3332,27 +4006,40 @@ }, "creator_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "Creator user ID. Filled by the server from the current user; do not provide." }, "creator_name": { - "type": "string" + "type": "string", + "description": "Creator name. Filled by the server; do not provide." }, "updater_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "Last updater user ID. Filled by the server; do not provide." }, "updater_name": { - "type": "string" + "type": "string", + "description": "Last updater name. Filled by the server; do not provide." }, "created_at": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Creation time as a Unix timestamp in seconds. Generated by the server; do not provide." }, "updated_at": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Last update time as a Unix timestamp in seconds. Generated by the server; do not provide." } - } + }, + "required": [ + "folder_id", + "name", + "ds_type", + "cron_pattern", + "rule_configs" + ] }, "AlertRuleAudit": { "type": "object", @@ -3374,7 +4061,8 @@ }, "account_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the account that owns the rule." }, "alert_rule_id": { "type": "integer", @@ -3383,7 +4071,11 @@ }, "action": { "type": "string", - "description": "Action performed, e.g. `create`, `update`." + "description": "Action performed: `create` = rule created; `update` = rule updated (covers full updates, field-batch updates, imports and moves).", + "enum": [ + "create", + "update" + ] }, "content": { "type": "string", @@ -3391,14 +4083,17 @@ }, "creator_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the user who made this change (taken from the rule's `updater_id` at change time)." }, "creator_name": { - "type": "string" + "type": "string", + "description": "Name of the user who made this change (taken from the rule's `updater_name` at change time)." }, "created_at": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "When this audit record was produced, as a Unix timestamp in seconds; equals the rule's `updated_at` at change time." } } }, @@ -3421,7 +4116,10 @@ "updater_name", "created_at", "updated_at", - "triggered" + "triggered", + "labels", + "timezone", + "active_alert_count" ], "properties": { "id": { @@ -3464,7 +4162,7 @@ }, "cron_pattern": { "type": "string", - "description": "5-field cron schedule, e.g. `* * * * *`. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." + "description": "Schedule expression: a 6-field cron with seconds, e.g. `0 * * * * *`, or an `@every 30s` interval descriptor. Must not start with `CRON_TZ=` or `TZ=`; use the `timezone` field instead." }, "timezone": { "type": "string", @@ -3477,29 +4175,54 @@ }, "creator_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the user who created the rule." }, "creator_name": { - "type": "string" + "type": "string", + "description": "Name of the user who created the rule." }, "updater_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the user who last modified the rule." }, "updater_name": { - "type": "string" + "type": "string", + "description": "Name of the user who last modified the rule." }, "created_at": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Creation time, as a Unix timestamp in seconds." }, "updated_at": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Last modification time, as a Unix timestamp in seconds." }, "triggered": { "type": "boolean", "description": "True if the rule currently has active alerts." + }, + "active_alert_count": { + "type": "integer", + "format": "int64", + "description": "Number of currently active (unrecovered) alerts fired by this rule. `triggered` equals `active_alert_count > 0`." + }, + "runtime_state": { + "type": "string", + "enum": [ + "disabled", + "offline", + "abnormal", + "stale", + "no_datasource", + "config_pending", + "waiting", + "normal" + ], + "description": "Runtime evaluation state, derived from edge heartbeats and the edge-reported rule status. Omitted when the state is unavailable.\n\n| Value | Meaning |\n|---|---|\n| `disabled` | The rule is disabled. |\n| `offline` | The edge instance or cluster owning this rule is offline. |\n| `abnormal` | The edge reports evaluation errors. |\n| `stale` | The edge's runtime status report is outdated. |\n| `no_datasource` | No datasource currently matches the rule's `ds_list` / `ds_ids`. |\n| `config_pending` | The latest rule config has not been delivered to the edge yet. |\n| `waiting` | Enabled, but the edge has not reported runtime status yet. |\n| `normal` | Evaluating normally. |" } } }, @@ -3515,11 +4238,13 @@ "properties": { "id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of this snapshot record." }, "account_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the account this snapshot belongs to." }, "num": { "type": "integer", @@ -3545,41 +4270,49 @@ ], "properties": { "name": { - "type": "string" + "type": "string", + "description": "Rule name, up to 128 characters when imported." }, "labels": { "type": "object", "additionalProperties": { "type": "string" - } + }, + "description": "Custom label key-value pairs attached to alert events produced by this rule." }, "ds_type": { - "type": "string" + "type": "string", + "description": "Datasource type ident, e.g. `prometheus`; must be a datasource type (`ident`) that exists in the import target environment." }, "ds_list": { "type": "array", "items": { "type": "string" - } + }, + "description": "Datasource name list with wildcard support; merged with `ds_ids` to decide which datasources the rule monitors — must be maintained by hand if a datasource is renamed." }, "ds_ids": { "type": "array", "items": { "type": "integer", "format": "uint64" - } + }, + "description": "Datasource ID list, merged with `ds_list`; references by ID and is therefore immune to datasource renames." }, "enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether the rule is enabled; rules imported as disabled are not evaluated." }, "debug_log_enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether to emit debug logs for this rule's evaluations; enable when troubleshooting." }, "rule_configs": { "$ref": "#/components/schemas/RuleConfigs" }, "cron_pattern": { - "type": "string" + "type": "string", + "description": "Evaluation schedule as a 6-field cron expression (seconds included) or `@every ` (an integral number of seconds, at least 1s); `CRON_TZ=`/`TZ=` prefixes are rejected — set the timezone in `timezone` instead." }, "timezone": { "type": "string", @@ -3587,37 +4320,44 @@ "default": "Asia/Shanghai" }, "delay_seconds": { - "type": "integer" + "type": "integer", + "description": "Query time offset in seconds: each evaluation reads data as of `schedule time − delay_seconds` to tolerate ingestion lag; `0` means no offset." }, "enabled_times": { "type": "array", "items": { "$ref": "#/components/schemas/EnabledTime" - } + }, + "description": "Effective time windows; each entry has `days` (0–6, 0 = Sunday) and `stime`/`etime` (`HH:MM`), interpreted in the rule's `timezone`; an empty list disables the rule." }, "annotations": { "type": "object", "additionalProperties": { "type": "string" - } + }, + "description": "Custom annotation key-value pairs attached to alert events; keys must not start with `$` (reserved for query field references)." }, "description_type": { "type": "string", "enum": [ "text", "markdown" - ] + ], + "description": "Format of `description`, `text` or `markdown`; treated as `text` when omitted." }, "description": { - "type": "string" + "type": "string", + "description": "Rule description in the format given by `description_type`, shown with alert events." }, "repeat_interval": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Interval in seconds between repeated notifications for a firing alert; values below 1 fall back to the default of 3600." }, "repeat_total": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Maximum number of repeated notifications for the same alert; values below 1 fall back to the default of 3." } } }, @@ -3664,10 +4404,12 @@ "properties": { "folder_id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the folder (grouping node)." }, "folder_name": { - "type": "string" + "type": "string", + "description": "Folder name; omitted by some endpoints (`omitempty`)." }, "rule_total": { "type": "integer", @@ -3690,24 +4432,30 @@ "description": "Default database for authentication." }, "username": { - "type": "string" + "type": "string", + "description": "ClickHouse authentication username." }, "password": { - "type": "string" + "type": "string", + "description": "ClickHouse authentication password." }, "open_conns": { - "type": "integer" + "type": "integer", + "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." }, "idle_conns": { - "type": "integer" + "type": "integer", + "description": "Maximum number of idle connections in the pool; `0` or omitted uses the default of 4." }, "lifetime_seconds": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." }, "timeout_mills": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." }, "max_execution_seconds": { "type": "integer", @@ -3720,31 +4468,36 @@ "description": "Dial timeout in milliseconds." }, "tls_enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether TLS is enabled; when `false`, all `tls_*` fields are cleared before saving." }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate." }, "tls_cert": { - "type": "string" + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." }, "tls_key": { - "type": "string" - }, - "tls_key_pwd": { - "type": "string" + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." }, "tls_skip_verify": { - "type": "boolean" + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." }, "tls_server_name": { - "type": "string" + "type": "string", + "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." }, "tls_min_version": { - "type": "string" + "type": "string", + "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." }, "tls_max_version": { - "type": "string" + "type": "string", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." } } }, @@ -3762,7 +4515,8 @@ }, "timeout_mills": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." }, "cloud_id": { "type": "string", @@ -3777,23 +4531,27 @@ "description": "Username for `self-managed` deployment." }, "password": { - "type": "string" + "type": "string", + "description": "Authentication password for self-managed clusters; ignored when `service_token` is set." }, "service_token": { "type": "string", "description": "Service token; overrides username/password if set." }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the Elasticsearch server certificate." }, "certificate_fingerprint": { - "type": "string" + "type": "string", + "description": "SHA-256 fingerprint of the Elasticsearch CA certificate, used to verify the server chain (the recommended check for ES 8 default security)." }, "headers": { "type": "array", "items": { "type": "string" - } + }, + "description": "Custom HTTP headers added to every request, each entry formatted as `Key: Value`." } } }, @@ -3802,49 +4560,58 @@ "description": "Loki datasource configuration. TLS fields are inherited from TLSClientConfig.", "properties": { "basic_auth_enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether HTTP Basic Auth is enabled; when `false`, `basic_auth_username`/`basic_auth_password` are ignored." }, "basic_auth_username": { - "type": "string" + "type": "string", + "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." }, "basic_auth_password": { - "type": "string" + "type": "string", + "description": "Basic Auth password, effective when `basic_auth_enabled` is `true`." }, "headers": { "type": "array", "items": { "type": "string" - } + }, + "description": "Custom HTTP headers added to every request, each entry formatted as `Key: Value`; usable for tenancy headers such as `X-Scope-OrgID`." }, "params": { "type": "array", "items": { "type": "string" - } + }, + "description": "Custom query parameters appended to every request URL, each entry formatted as `key=value`." }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate." }, "tls_cert": { - "type": "string" + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." }, "tls_key": { - "type": "string" - }, - "tls_key_pwd": { - "type": "string" + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." }, "tls_skip_verify": { - "type": "boolean" + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." }, "tls_server_name": { - "type": "string" + "type": "string", + "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." }, "tls_min_version": { - "type": "string" + "type": "string", + "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." }, "tls_max_version": { - "type": "string" + "type": "string", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." } } }, @@ -3853,10 +4620,12 @@ "description": "MySQL datasource configuration. TLS fields are inherited from TLSClientConfig.", "properties": { "username": { - "type": "string" + "type": "string", + "description": "MySQL authentication username." }, "password": { - "type": "string" + "type": "string", + "description": "MySQL authentication password." }, "open_conns": { "type": "integer", @@ -3876,29 +4645,42 @@ "format": "int64", "description": "Query timeout in milliseconds." }, + "tls_mode": { + "type": "string", + "enum": [ + "disable", + "require", + "verify-full" + ], + "description": "TLS mode for the MySQL connection. Empty keeps the legacy per-field TLS behavior. `disable` = no TLS (all `tls_*` fields are cleared on save); `require` = TLS without server certificate verification; `verify-full` = TLS with full server verification (CA chain and hostname). MySQL has no `verify-ca` — verifying the CA implies verifying the hostname." + }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate; only allowed when `tls_mode` is `verify-full` (or empty legacy mode)." }, "tls_cert": { - "type": "string" + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." }, "tls_key": { - "type": "string" - }, - "tls_key_pwd": { - "type": "string" + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." }, "tls_skip_verify": { - "type": "boolean" + "type": "boolean", + "description": "Whether to skip server certificate verification; derived from `tls_mode` when set (`require` → `true`, `verify-full` → `false`) — only manually effective under legacy empty `tls_mode`." }, "tls_server_name": { - "type": "string" + "type": "string", + "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." }, "tls_min_version": { - "type": "string" + "type": "string", + "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." }, "tls_max_version": { - "type": "string" + "type": "string", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." } } }, @@ -3907,10 +4689,12 @@ "description": "Oracle datasource configuration.", "properties": { "username": { - "type": "string" + "type": "string", + "description": "Oracle authentication username." }, "password": { - "type": "string" + "type": "string", + "description": "Oracle authentication password." }, "options": { "type": "object", @@ -3920,18 +4704,22 @@ "description": "Extra connection options as key-value pairs." }, "open_conns": { - "type": "integer" + "type": "integer", + "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." }, "idle_conns": { - "type": "integer" + "type": "integer", + "description": "Maximum number of idle connections in the pool; `0` or omitted uses the default of 4." }, "lifetime_seconds": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." }, "timeout_mills": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." } } }, @@ -3965,6 +4753,10 @@ }, "victorialogs": { "$ref": "#/components/schemas/DSVictoriaLogsConfig" + }, + "tencent_cls": { + "$ref": "#/components/schemas/DSTencentCLSConfig", + "description": "Tencent CLS credentials. Required when `type_ident` is `tencent_cls`." } } }, @@ -3973,33 +4765,52 @@ "description": "PostgreSQL datasource configuration.", "properties": { "username": { - "type": "string" + "type": "string", + "description": "PostgreSQL authentication username." }, "password": { - "type": "string" + "type": "string", + "description": "PostgreSQL authentication password." }, "open_conns": { - "type": "integer" + "type": "integer", + "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." }, "idle_conns": { - "type": "integer" + "type": "integer", + "description": "Maximum number of idle connections in the pool; `0` or omitted uses the default of 4." }, "lifetime_seconds": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." }, "timeout_mills": { "type": "integer", - "format": "int64" + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + }, + "ssl_mode": { + "type": "string", + "enum": [ + "disable", + "require", + "verify-ca", + "verify-full" + ], + "description": "SSL mode for the PostgreSQL connection. Empty keeps the legacy behavior inferred from `tls_ca`. `disable` = no TLS (all `tls_*` fields are cleared on save); `require` = TLS without server certificate verification (`tls_ca` not allowed); `verify-ca` = verify the server certificate CA chain but not the hostname; `verify-full` = verify both CA chain and hostname." }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate; used with `ssl_mode` `verify-ca`/`verify-full` and rejected under `require`." }, "tls_cert": { - "type": "string" + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." }, "tls_key": { - "type": "string" + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." } } }, @@ -4034,28 +4845,32 @@ "description": "Custom query parameters in `key=value` format." }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate." }, "tls_cert": { - "type": "string" + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." }, "tls_key": { - "type": "string" - }, - "tls_key_pwd": { - "type": "string" + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." }, "tls_skip_verify": { - "type": "boolean" + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." }, "tls_server_name": { - "type": "string" + "type": "string", + "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." }, "tls_min_version": { - "type": "string" + "type": "string", + "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." }, "tls_max_version": { - "type": "string" + "type": "string", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." } } }, @@ -4093,7 +4908,8 @@ "properties": { "id": { "type": "integer", - "format": "uint64" + "format": "uint64", + "description": "ID of the datasource type record." }, "name": { "type": "string", @@ -4119,49 +4935,58 @@ "description": "VictoriaLogs datasource configuration. TLS fields are inherited from TLSClientConfig.", "properties": { "basic_auth_enabled": { - "type": "boolean" + "type": "boolean", + "description": "Whether HTTP Basic Auth is enabled; when `false`, `basic_auth_username`/`basic_auth_password` are ignored." }, "basic_auth_username": { - "type": "string" + "type": "string", + "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." }, "basic_auth_password": { - "type": "string" + "type": "string", + "description": "Basic Auth password, effective when `basic_auth_enabled` is `true`." }, "headers": { "type": "array", "items": { "type": "string" - } + }, + "description": "Custom HTTP headers added to every request, each entry formatted as `Key: Value`; usable for tenancy headers such as `AccountID`/`ProjectID`." }, "params": { "type": "array", "items": { "type": "string" - } + }, + "description": "Custom query parameters appended to every request URL, each entry formatted as `key=value`." }, "tls_ca": { - "type": "string" + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate." }, "tls_cert": { - "type": "string" + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." }, "tls_key": { - "type": "string" - }, - "tls_key_pwd": { - "type": "string" + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." }, "tls_skip_verify": { - "type": "boolean" + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." }, "tls_server_name": { - "type": "string" + "type": "string", + "description": "Server name used for TLS SNI and certificate verification; defaults to the host from the connection address when empty." }, "tls_min_version": { - "type": "string" + "type": "string", + "description": "Minimum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint and it must not exceed `tls_max_version`." }, "tls_max_version": { - "type": "string" + "type": "string", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." } } }, @@ -4177,7 +5002,8 @@ "note", "address", "edge_cluster_name", - "updated_at" + "updated_at", + "payload" ], "properties": { "id": { @@ -4192,7 +5018,7 @@ }, "type_ident": { "type": "string", - "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `victorialogs`." + "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`." }, "name": { "type": "string", @@ -4211,7 +5037,15 @@ "description": "Connection address. For Prometheus/Loki/VictoriaLogs: HTTP URL. For MySQL/Oracle/Postgres/ClickHouse: `host:port`. For SLS: endpoint without http/https prefix." }, "payload": { - "$ref": "#/components/schemas/DSPayload" + "anyOf": [ + { + "$ref": "#/components/schemas/DSPayload" + }, + { + "type": "null" + } + ], + "description": "Type-specific configuration block; must contain the key matching `type_ident`. Always `null` in `/monit/datasource/list` responses (the list query does not read the payload column); populated in create/update/info responses. For `tencent_cls`, `secret_key` is masked to an empty string unless it is an `${env:...}` reference." }, "edge_cluster_name": { "type": "string", @@ -4230,13 +5064,13 @@ "properties": { "type": { "type": "string", - "description": "Filter by datasource type identifier. Omit to return all types. Allowed values: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `victorialogs`." + "description": "Filter by datasource type identifier. Omit to return all types. Allowed values: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`." } } }, "DataSourceListResponse": { "type": "array", - "description": "List of datasources. Sensitive credential fields are omitted.", + "description": "List of datasources. The `payload` column is not read by this endpoint, so `payload` is `null` in every item.", "items": { "$ref": "#/components/schemas/DataSourceItem" } @@ -4258,11 +5092,11 @@ }, "type_ident": { "type": "string", - "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `victorialogs`." + "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`." }, "name": { "type": "string", - "description": "Datasource display name." + "description": "Datasource display name. This is the name referenced as `ds_name` in query and diagnose APIs." }, "note": { "type": "string", @@ -4270,7 +5104,7 @@ }, "address": { "type": "string", - "description": "Connection address. For Prometheus/Loki/VictoriaLogs: HTTP URL. For MySQL/Oracle/Postgres/ClickHouse: `host:port`. For SLS: endpoint without http/https prefix. Not required for Elasticsearch cloud deployment." + "description": "Connection address. Required for every type except `elasticsearch` with `deployment: cloud`. Prometheus/Loki/VictoriaLogs: HTTP URL; MySQL/Oracle/Postgres/ClickHouse: `host:port`; SLS: endpoint without the `http(s)://` prefix; `tencent_cls`: must be `cls.tencentcloudapi.com` or `cls.internal.tencentcloudapi.com` (requires Monitors edge >= v0.66.0)." }, "payload": { "$ref": "#/components/schemas/DSPayload", @@ -4279,6 +5113,10 @@ "edge_cluster_name": { "type": "string", "description": "Monitors edge cluster name responsible for evaluating rules using this datasource." + }, + "enabled": { + "type": "boolean", + "description": "Whether the datasource is enabled for rule evaluation. When omitted on create, the datasource is created disabled (`false`)." } } }, @@ -4300,16 +5138,6 @@ "message" ] }, - "EmptyObject": { - "type": "object", - "description": "An empty object. Returned as the `data` payload by operations whose success signal is simply the absence of an error.", - "additionalProperties": false - }, - "EmptyRequest": { - "type": "object", - "description": "No parameters required.", - "additionalProperties": false - }, "EmptyResponse": { "type": "object", "description": "Empty response body. The server returns `data: null` on success.", @@ -4391,7 +5219,8 @@ "properties": { "request_id": { "type": "string", - "example": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" + "example": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "description": "Unique trace ID of this request; include it when reporting issues so logs can be located." }, "error": { "$ref": "#/components/schemas/DutyError" @@ -4412,7 +5241,7 @@ "id": { "type": "integer", "format": "uint64", - "description": "Resource ID." + "description": "Numeric ID of the target resource; the exact meaning depends on the API being called (e.g. datasource ID, ruleset ID)." } } }, @@ -4469,22 +5298,26 @@ "type": "array", "items": { "type": "string" - } + }, + "description": "Result fields that become alert event labels — identical label sets collapse into one alert; must not overlap `value_fields`; applies to table-shaped results (SQL/ES-style datasources)." }, "value_fields": { "type": "array", "items": { "type": "string" - } + }, + "description": "Numeric result fields used in threshold evaluation (referenced as `$A.` in threshold expressions); required for threshold checks unless the datasource is `prometheus`/`loki`/`victorialogs`; field names must not contain `.`." }, "args": { "type": "object", "additionalProperties": { "type": "string" - } + }, + "description": "Datasource-specific query options keyed by the `.