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..101b84cf 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": { @@ -196,12 +200,12 @@ "post": { "operationId": "monit-datasource-write-create", "summary": "Create datasource", - "description": "Create a new monitoring data source. The `payload` must include the type-specific configuration block.", + "description": "Create a new monitoring data source. The `payload` must include the type-specific configuration block. Supports diagnostic types redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka; enabled and alerting_enabled are independent.", "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 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`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`.\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. Use credential fields only for connection credentials.\n\nSee the request/response schemas for all supported types and credential handling. Diagnostic-only types cannot enable alerting. On create omitted enabled defaults to true; on update omission preserves the current value. Explicit null for enabled or alerting_enabled is invalid. Diagnostic passwords and Kafka private keys are omitted from responses unless they are environment references; omit these secrets on update to preserve them, or send an empty string to clear. Other datasource credentials may be returned and must be handled as sensitive.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-create", "metadata": { "sidebarTitle": "Create datasource" @@ -235,7 +239,8 @@ "name": "Prometheus Prod", "enabled": true, "edge_cluster_name": "default", - "updated_at": 1712000000 + "updated_at": 1712000000, + "alerting_enabled": true } } } @@ -282,12 +287,12 @@ "post": { "operationId": "monit-datasource-write-update", "summary": "Update datasource", - "description": "Update an existing data source. Supply `id` plus the fields to change.", + "description": "Update an existing data source. Supply `id` plus the fields to change. Supports diagnostic types redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka; enabled and alerting_enabled are independent.", "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 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. Use credential fields only for connection credentials.\n\nSee the request/response schemas for all supported types and credential handling. Diagnostic-only types cannot enable alerting. On create omitted enabled defaults to true; on update omission preserves the current value. Explicit null for enabled or alerting_enabled is invalid. Diagnostic passwords and Kafka private keys are omitted from responses unless they are environment references; omit these secrets on update to preserve them, or send an empty string to clear. Other datasource credentials may be returned and must be handled as sensitive.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-update", "metadata": { "sidebarTitle": "Update datasource" @@ -321,7 +326,8 @@ "name": "Prometheus Prod v2", "enabled": true, "edge_cluster_name": "default", - "updated_at": 1712100000 + "updated_at": 1712100000, + "alerting_enabled": true } } } @@ -374,7 +380,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 +604,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 +780,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 +839,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 +848,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 +884,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *" + "cron_pattern": "0 * * * * *" } ] } @@ -1052,12 +1001,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. Supports diagnostic types redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka; enabled and alerting_enabled are independent.", "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\nSee the request/response schemas for all supported types and credential handling. Diagnostic-only types cannot enable alerting. On create omitted enabled defaults to true; on update omission preserves the current value. Explicit null for enabled or alerting_enabled is invalid. Diagnostic passwords and Kafka private keys are omitted from responses unless they are environment references; omit these secrets on update to preserve them, or send an empty string to clear. Other datasource credentials may be returned and must be handled as sensitive.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-info", "metadata": { "sidebarTitle": "Get datasource detail" @@ -1102,7 +1051,8 @@ } }, "edge_cluster_name": "default", - "updated_at": 1712000000 + "updated_at": 1712000000, + "alerting_enabled": true } } } @@ -1262,7 +1212,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "channel_ids": [ 20001 ] @@ -1454,7 +1404,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 +1469,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "rule_configs": { "queries": [ { @@ -1610,7 +1560,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "rule_configs": { "queries": [ { @@ -1635,7 +1585,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 +1652,7 @@ "prometheus*" ], "enabled": true, - "cron_pattern": "* * * * *", + "cron_pattern": "0 * * * * *", "channel_ids": [ 20001 ], @@ -2002,7 +1952,9 @@ "ds_type": "prometheus", "enabled": true, "triggered": true, - "created_at": 1710000000 + "created_at": 1710000000, + "active_alert_count": 2, + "runtime_state": "normal" } ] } @@ -2202,12 +2154,12 @@ "post": { "operationId": "monit-datasource-read-list", "summary": "List datasources", - "description": "Return all data sources for the current account. Optionally filter by `type_ident`.", + "description": "Return all data sources for the current account. Optionally filter by `type_ident`. Supports diagnostic types redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka; enabled and alerting_enabled are independent.", "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`) |\n\n## Usage\n\n- Omit `type_ident` to return all types.\n- Sensitive credential fields (passwords, keys) are not returned in the list response.", + "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## Usage\n\n- Omit `type_ident` to return all types.\n- Sensitive credential fields (passwords, keys) are not returned in the list response.\n\nSee the request/response schemas for all supported types and credential handling. Diagnostic-only types cannot enable alerting. On create omitted enabled defaults to true; on update omission preserves the current value. Explicit null for enabled or alerting_enabled is invalid. Diagnostic passwords and Kafka private keys are omitted from responses unless they are environment references; omit these secrets on update to preserve them, or send an empty string to clear. Other datasource credentials may be returned and must be handled as sensitive.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-list", "metadata": { "sidebarTitle": "List datasources" @@ -2245,7 +2197,9 @@ "note": "Production Prometheus", "address": "http://prometheus.example.com:9090", "edge_cluster_name": "default", - "updated_at": 1712000000 + "updated_at": 1712000000, + "payload": null, + "alerting_enabled": true } ] } @@ -2436,19 +2390,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 +2410,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 +2436,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/QueryRowsResponse" + "$ref": "#/components/schemas/QueryDataResponse" } } } @@ -2490,18 +2444,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 +2468,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" + } + } + } } } } @@ -2525,12 +2517,12 @@ "post": { "operationId": "monit-read-query-diagnose", "summary": "Diagnose data source", - "description": "Run a synchronous diagnostic query (`log_patterns` for Loki/VictoriaLogs, `metric_trends` for Prometheus). Used by Flashduty AI SRE for log-pattern clustering and time-series trend analysis. Long-running — up to 35 s.", + "description": "Run a synchronous diagnostic query (`log_patterns` for Loki/VictoriaLogs, `metric_trends` for Prometheus). Used by Flashduty AI SRE for log-pattern clustering and time-series trend analysis. Long-running — up to 35 s.\n\nDeprecated: migrate to /monit/datasource/tools/invoke with prometheus.metric_trends, loki.log_patterns or victorialogs.log_patterns. Retained for existing consumers; the legacy request and response remain unchanged.", "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- 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 +2589,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": [] } ] } @@ -2669,19 +2691,20 @@ "500": { "$ref": "#/components/responses/ServerError" } - } + }, + "deprecated": true } }, "/monit/tools/catalog": { "post": { "operationId": "monit-read-tools-catalog", "summary": "List target tool catalog", - "description": "Look up the tools that the per-target monit-agent currently exposes for a given `target_locator` (host, mysql, …). Returns each tool's name, description, and JSON-Schema `input_schema`. Pair with `/monit/tools/invoke` to drive AI-SRE tool calls.", + "description": "Look up the tools that the per-target monit-agent currently exposes for a given `target_locator` (host). Returns each tool's name, description, and JSON-Schema `input_schema`. Pair with `/monit/tools/invoke` to drive AI-SRE tool calls. Agent targets are host-only. Remote datasource evidence uses /monit/datasource/tools/invoke and datasource_id.", "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- 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 +2719,7 @@ }, "example": { "account_id": 10001, - "target_locator": "web-01", - "include_output_shape": true + "target_locator": "web-01" } } } @@ -2733,34 +2755,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 + ] } } } @@ -2785,12 +2808,12 @@ "post": { "operationId": "monit-read-tools-invoke", "summary": "Invoke target tools", - "description": "Invoke up to 8 monit-agent tools concurrently on a single target. Results come back in the order of the input `tools` array. Long-running — individual tools have per-tool timeouts on the agent and the whole request may take tens of seconds.", + "description": "Invoke up to 8 monit-agent tools concurrently on a single target. Results come back in the order of the input `tools` array. Long-running — individual tools have per-tool timeouts on the agent and the whole request may take tens of seconds. Agent targets are host-only. Remote datasource evidence uses /monit/datasource/tools/invoke and datasource_id.", "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- 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 +2876,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 + ] } } } @@ -2906,7 +2935,7 @@ "post": { "operationId": "monit-read-targets-list", "summary": "List monitored targets", - "description": "List the targets observed under the current tenant by the monit-agent route projection. Supports `target_locator` prefix search and cursor pagination. Use this to drive `target_locator` selection for `/monit/tools/catalog` and `/monit/tools/invoke`.", + "description": "List the targets observed under the current tenant by the monit-agent route projection. Supports `target_locator` prefix search and cursor pagination. Use this to drive `target_locator` selection for `/monit/tools/catalog` and `/monit/tools/invoke`. Agent targets are host-only. Remote datasource evidence uses /monit/datasource/tools/invoke and datasource_id.", "tags": [ "Monitors/Diagnostics" ], @@ -2986,19 +3015,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 +3044,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/PreviewSyncResponse" + "$ref": "#/components/schemas/ServiceMapStatusResponse" } } } @@ -3024,11 +3053,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 +3117,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "503": { + "$ref": "#/components/responses/ServiceUnavailable" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3052,2689 +3132,6610 @@ "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": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "missingAppKey": { - "value": { + } + }, + "/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", - "error": { - "code": "Unauthorized", - "message": "You are unauthorized." + "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" } - } - }, - "Forbidden": { - "description": "The app_key is valid but lacks permission for this operation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "noEditPermission": { - "value": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "AccessDenied", - "message": "Access Denied." - } + }, + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceMapSummaryRequest" + }, + "example": { + "anchor": { + "host_id": "host_0123456789abcdef0123456789abcdef" } } } } } - }, - "NotFound": { - "description": "The referenced resource does not exist or has been deleted. Note: Flashduty historically returns HTTP 400 with code `ResourceNotFound` for missing domain entities; a true 404 is reserved for unknown routes.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "resourceMissing": { - "value": { + } + }, + "/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", - "error": { - "code": "ResourceNotFound", - "message": "The resource you request is not found" + "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" } - } - }, - "TooManyRequests": { - "description": "Rate limit hit. Either the global API limit, a per-account limit, or a per-integration limit.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "rateLimited": { - "value": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "error": { - "code": "RequestTooFrequently", - "message": "Request too frequently." - } - } + }, + "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" + ] } } } } - }, - "ServerError": { - "description": "Unexpected server-side error. Include the request_id when reporting.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - }, - "examples": { - "internal": { - "value": { + } + }, + "/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", - "error": { - "code": "InternalError", - "message": "We encountered an internal error, and it has been reported. Please try again later." + "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 } } } } - } - } - } - }, - "schemas": { - "AlertRule": { - "type": "object", - "description": "Full alert rule configuration.", - "properties": { - "id": { - "type": "integer", - "format": "uint64" }, - "account_id": { - "type": "integer", - "format": "uint64" + "400": { + "$ref": "#/components/responses/BadRequest" }, - "folder_id": { - "type": "integer", - "format": "uint64", - "description": "Folder the rule belongs to." + "401": { + "$ref": "#/components/responses/Unauthorized" }, - "name": { - "type": "string", - "description": "Rule name." + "503": { + "$ref": "#/components/responses/ServiceUnavailable" }, - "labels": { + "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" + ] + } + } + } + } + } + }, + "/monit/datasource/tools/invoke": { + "post": { + "description": "Execute one deterministic tool against a configured datasource. Requires all currently online routable Edge sessions in the cluster to support the v0.71.0 base invoke protocol; individual tools may require a newer implementation. No tool catalog, automatic replay, or fallback to Agent/legacy diagnose. Request body limit 128 KiB; complete success response limit 1 MiB; tool timeout at most 25 seconds.", + "operationId": "monit-datasource-tools-invoke", + "requestBody": { + "content": { + "application/json": { + "example": { + "datasource_id": 10, + "params": {}, + "tool": "mysql.overview" + }, + "schema": { + "$ref": "#/components/schemas/DatasourceToolInvokeRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "example": { + "data": { + "data": { + "version": "8.0.36" + }, + "datasource_id": 10, + "summary": "MySQL overview", + "tool": "mysql.overview" + }, + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" + }, + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/SuccessEnvelope" + }, + { + "properties": { + "data": { + "$ref": "#/components/schemas/DatasourceToolResult" + } + }, + "type": "object" + } + ] + } + } + }, + "description": "Success" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: invalid_request, tool_not_supported, datasource_error." + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "403": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: access_denied." + }, + "404": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: datasource_not_found." + }, + "409": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: datasource_disabled, datasource_in_use." + }, + "413": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: source_too_large, result_too_large." + }, + "429": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: overloaded." + }, + "499": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: canceled." + }, + "500": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: internal." + }, + "503": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: no_active_edge, edge_upgrade_required, mixed_edge_versions." + }, + "504": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "description": "Standard HTTP error; error.reason: timeout." + } + }, + "summary": "Invoke datasource tool", + "tags": [ + "Monitors/Data sources" + ], + "x-mint": { + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **2,000 requests/minute**; **32 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |\n\nUse datasource IDs from `/monit/datasource/list`. Disabled datasources return `datasource_disabled`; `alerting_enabled=false` does not block tools. Errors use non-2xx HTTP status and `error.code`, `error.message`, `error.reason`. `tool_not_supported` indicates the selected executor does not provide this tool; it is not a vendor permission error. Never retry through another Edge or the legacy diagnose endpoint automatically.", + "href": "/en/api-reference/monitors/data-sources/monit-datasource-tools-invoke", + "metadata": { + "sidebarTitle": "Invoke datasource tool" + } + } + } + } + }, + "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": { + "missingAppKey": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "Unauthorized", + "message": "You are unauthorized." + } + } + } + } + } + } + }, + "Forbidden": { + "description": "The app_key is valid but lacks permission for this operation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "noEditPermission": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "AccessDenied", + "message": "Access Denied." + } + } + } + } + } + } + }, + "NotFound": { + "description": "The referenced resource does not exist or has been deleted. Note: Flashduty historically returns HTTP 400 with code `ResourceNotFound` for missing domain entities; a true 404 is reserved for unknown routes.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "resourceMissing": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "ResourceNotFound", + "message": "The resource you request is not found" + } + } + } + } + } + } + }, + "TooManyRequests": { + "description": "Rate limit hit. Either the global API limit, a per-account limit, or a per-integration limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "rateLimited": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "RequestTooFrequently", + "message": "Request too frequently." + } + } + } + } + } + } + }, + "ServerError": { + "description": "Unexpected server-side error. Include the request_id when reporting.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + }, + "examples": { + "internal": { + "value": { + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "error": { + "code": "InternalError", + "message": "We encountered an internal error, and it has been reported. Please try again later." + } + } + } + } + } + } + }, + "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", + "description": "Rule ID. Required for update; omit for create (assigned by the server)." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "Account ID. Filled by the server from the authenticated identity; do not provide." + }, + "folder_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the folder the rule belongs to. Obtainable via `POST /monit/folder/list`." + }, + "name": { + "type": "string", + "description": "Rule name. Must be unique within the same folder." + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom labels." + }, + "ds_type": { + "type": "string", + "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). 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", + "items": { + "type": "integer", + "format": "uint64" + }, + "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", + "description": "Whether the rule is enabled. Updating to `false` makes the server clean up the rule's active alerts." + }, + "debug_log_enabled": { + "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", + "description": "Check configuration: query list plus trigger/recovery conditions. Structure see `RuleConfigs`." + }, + "cron_pattern": { + "type": "string", + "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", + "description": "Timezone in which the rule executes. Determines how the cron schedule and effective time windows are interpreted. Only IANA timezone names are accepted (e.g. `Asia/Shanghai`, `UTC`, `Europe/London`); shortcuts and offsets such as `Local`, `UTC+8`, or `CST` are rejected. Treated as `Asia/Shanghai` if empty.", + "default": "Asia/Shanghai" + }, + "delay_seconds": { + "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. 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": { + "days": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "Days of week (0=Sunday)." + }, + "stime": { + "type": "string", + "description": "Start time, e.g. `09:00`." + }, + "etime": { + "type": "string", + "description": "End time, e.g. `18:00`." + } + } + } + }, + "annotations": { + "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", + "description": "Rule description, in Markdown." + }, + "channel_ids": { + "type": "array", + "items": { + "type": "integer", + "format": "uint64" + }, + "description": "Channel IDs to send alerts to." + }, + "repeat_interval": { + "type": "integer", + "format": "int64", + "description": "Notification repeat interval in seconds." + }, + "repeat_total": { + "type": "integer", + "format": "int64", + "description": "Max number of repeat notifications." + }, + "creator_id": { + "type": "integer", + "format": "uint64", + "description": "Creator user ID. Filled by the server from the current user; do not provide." + }, + "creator_name": { + "type": "string", + "description": "Creator name. Filled by the server; do not provide." + }, + "updater_id": { + "type": "integer", + "format": "uint64", + "description": "Last updater user ID. Filled by the server; do not provide." + }, + "updater_name": { + "type": "string", + "description": "Last updater name. Filled by the server; do not provide." + }, + "created_at": { + "type": "integer", + "format": "int64", + "description": "Creation time as a Unix timestamp in seconds. Generated by the server; do not provide." + }, + "updated_at": { + "type": "integer", + "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", + "description": "An audit record capturing a rule snapshot at a point in time.", + "required": [ + "id", + "account_id", + "alert_rule_id", + "action", + "creator_id", + "creator_name", + "created_at" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "Audit record ID." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the account that owns the rule." + }, + "alert_rule_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the alert rule this record belongs to." + }, + "action": { + "type": "string", + "description": "Action performed: `create` = rule created; `update` = rule updated (covers full updates, field-batch updates, imports and moves).", + "enum": [ + "create", + "update" + ] + }, + "content": { + "type": "string", + "description": "JSON string of the full rule snapshot at audit time. Populated on `/monit/rule/audit/detail`, omitted on list responses." + }, + "creator_id": { + "type": "integer", + "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", + "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", + "description": "When this audit record was produced, as a Unix timestamp in seconds; equals the rule's `updated_at` at change time." + } + } + }, + "AlertRuleBasic": { + "type": "object", + "description": "Basic alert rule information for list views.", + "required": [ + "id", + "account_id", + "folder_id", + "name", + "ds_type", + "enabled", + "debug_log_enabled", + "cron_pattern", + "delay_seconds", + "creator_id", + "creator_name", + "updater_id", + "updater_name", + "created_at", + "updated_at", + "triggered", + "labels", + "timezone", + "active_alert_count" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "Unique rule ID." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "Account ID." + }, + "folder_id": { + "type": "integer", + "format": "uint64", + "description": "Folder ID." + }, + "name": { + "type": "string", + "description": "Rule name." + }, + "labels": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Custom labels." + }, + "ds_type": { + "type": "string", + "description": "Data source type, e.g. `prometheus`." + }, + "enabled": { + "type": "boolean", + "description": "Whether the rule is enabled." + }, + "debug_log_enabled": { + "type": "boolean", + "description": "Whether debug logging is enabled." + }, + "cron_pattern": { + "type": "string", + "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", + "description": "Timezone in which the rule executes. Determines how the cron schedule and effective time windows are interpreted. Only IANA timezone names are accepted (e.g. `Asia/Shanghai`, `UTC`, `Europe/London`); shortcuts and offsets such as `Local`, `UTC+8`, or `CST` are rejected. Treated as `Asia/Shanghai` if empty.", + "default": "Asia/Shanghai" + }, + "delay_seconds": { + "type": "integer", + "description": "Evaluation delay in seconds." + }, + "creator_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the user who created the rule." + }, + "creator_name": { + "type": "string", + "description": "Name of the user who created the rule." + }, + "updater_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the user who last modified the rule." + }, + "updater_name": { + "type": "string", + "description": "Name of the user who last modified the rule." + }, + "created_at": { + "type": "integer", + "format": "int64", + "description": "Creation time, as a Unix timestamp in seconds." + }, + "updated_at": { + "type": "integer", + "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. |" + } + } + }, + "AlertRuleCounter": { + "type": "object", + "description": "One historical snapshot of the account's alert rule total.", + "required": [ + "id", + "account_id", + "num", + "clock" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "ID of this snapshot record." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the account this snapshot belongs to." + }, + "num": { + "type": "integer", + "format": "int64", + "description": "Rule count at the sample time." + }, + "clock": { + "type": "integer", + "format": "int64", + "description": "Sample timestamp, Unix epoch seconds." + } + } + }, + "AlertRuleExport": { + "type": "object", + "description": "Portable alert rule representation for import/export. Omits identifying fields like `id`, `account_id`, and audit metadata.", + "required": [ + "name", + "ds_type", + "enabled", + "debug_log_enabled", + "cron_pattern" + ], + "properties": { + "name": { + "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", + "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", + "description": "Whether the rule is enabled; rules imported as disabled are not evaluated." + }, + "debug_log_enabled": { + "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", + "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", + "description": "Timezone in which the rule executes. IANA timezone name; defaults to `Asia/Shanghai`.", + "default": "Asia/Shanghai" + }, + "delay_seconds": { + "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", + "description": "Rule description in the format given by `description_type`, shown with alert events." + }, + "repeat_interval": { + "type": "integer", + "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", + "description": "Maximum number of repeated notifications for the same alert; values below 1 fall back to the default of 3." + } + } + }, + "AlertRuleExportListResponse": { + "type": "array", + "description": "List of exported rule configurations, compatible with `POST /monit/rule/import`.", + "items": { + "$ref": "#/components/schemas/AlertRuleExport" + } + }, + "AlertRuleInfoResponse": { + "allOf": [ + { + "$ref": "#/components/schemas/AlertRule" + } + ], + "description": "Full alert rule returned by the info endpoint. All server-assigned fields are guaranteed present.", + "required": [ + "id", + "account_id", + "folder_id", + "name", + "ds_type", + "enabled", + "debug_log_enabled", + "cron_pattern", + "delay_seconds", + "creator_id", + "creator_name", + "updater_id", + "updater_name", + "created_at", + "updated_at" + ] + }, + "AlertRuleStatus": { + "type": "object", + "description": "Rule trigger status for a folder node.", + "required": [ + "folder_id", + "rule_total", + "triggered_rule_count" + ], + "properties": { + "folder_id": { + "type": "integer", + "format": "uint64", + "description": "ID of the folder (grouping node)." + }, + "folder_name": { + "type": "string", + "description": "Folder name; omitted by some endpoints (`omitempty`)." + }, + "rule_total": { + "type": "integer", + "format": "int64", + "description": "Total rules in the folder family." + }, + "triggered_rule_count": { + "type": "integer", + "format": "int64", + "description": "Rules with active alerts." + } + } + }, + "DSClickHouseConfig": { + "type": "object", + "description": "ClickHouse datasource configuration. TLS fields are inherited from TLSClientConfig.", + "properties": { + "database": { + "type": "string", + "description": "Default database for authentication." + }, + "username": { + "type": "string", + "description": "ClickHouse authentication username." + }, + "password": { + "type": "string", + "description": "ClickHouse authentication password." + }, + "open_conns": { + "type": "integer", + "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." + }, + "idle_conns": { + "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", + "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." + }, + "timeout_mills": { + "type": "integer", + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + }, + "max_execution_seconds": { + "type": "integer", + "format": "int64", + "description": "Max query execution time in seconds." + }, + "dial_timeout_mills": { + "type": "integer", + "format": "int64", + "description": "Dial timeout in milliseconds." + }, + "tls_enabled": { + "type": "boolean", + "description": "Whether TLS is enabled; when `false`, all `tls_*` fields are cleared before saving." + }, + "tls_ca": { + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate." + }, + "tls_cert": { + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + }, + "tls_key": { + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + }, + "tls_server_name": { + "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", + "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", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + } + } + }, + "DSElasticSearchConfig": { + "type": "object", + "description": "Elasticsearch datasource configuration.", + "properties": { + "deployment": { + "type": "string", + "enum": [ + "cloud", + "self-managed" + ], + "description": "Deployment type. `cloud` uses Elastic Cloud; `self-managed` uses a self-hosted cluster." + }, + "timeout_mills": { + "type": "integer", + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + }, + "cloud_id": { + "type": "string", + "description": "Elastic Cloud deployment ID. Only for `cloud` deployment." + }, + "api_key": { + "type": "string", + "description": "Elastic Cloud API key. Only for `cloud` deployment." + }, + "username": { + "type": "string", + "description": "Username for `self-managed` deployment." + }, + "password": { + "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", + "description": "PEM-encoded CA certificate used to verify the Elasticsearch server certificate." + }, + "certificate_fingerprint": { + "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`." + } + } + }, + "DSLokiConfig": { + "type": "object", + "description": "Loki datasource configuration. TLS fields are inherited from TLSClientConfig.", + "properties": { + "basic_auth_enabled": { + "type": "boolean", + "description": "Whether HTTP Basic Auth is enabled; when `false`, `basic_auth_username`/`basic_auth_password` are ignored." + }, + "basic_auth_username": { + "type": "string", + "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." + }, + "basic_auth_password": { + "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", + "description": "PEM-encoded CA certificate used to verify the server certificate." + }, + "tls_cert": { + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + }, + "tls_key": { + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + }, + "tls_server_name": { + "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", + "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", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + } + } + }, + "DSMySQLConfig": { + "type": "object", + "description": "MySQL datasource configuration. TLS fields are inherited from TLSClientConfig.", + "properties": { + "username": { + "type": "string", + "description": "MySQL authentication username." + }, + "password": { + "type": "string", + "description": "MySQL authentication password." + }, + "open_conns": { + "type": "integer", + "description": "Maximum open connections." + }, + "idle_conns": { + "type": "integer", + "description": "Maximum idle connections." + }, + "lifetime_seconds": { + "type": "integer", + "format": "int64", + "description": "Connection maximum lifetime in seconds." + }, + "timeout_mills": { + "type": "integer", + "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", + "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", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + }, + "tls_key": { + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + }, + "tls_skip_verify": { + "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", + "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", + "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", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + } + } + }, + "DSOracleConfig": { + "type": "object", + "description": "Oracle datasource configuration.", + "properties": { + "username": { + "type": "string", + "description": "Oracle authentication username." + }, + "password": { + "type": "string", + "description": "Oracle authentication password." + }, + "options": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Extra connection options as key-value pairs." + }, + "open_conns": { + "type": "integer", + "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." + }, + "idle_conns": { + "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", + "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." + }, + "timeout_mills": { + "type": "integer", + "format": "int64", + "description": "Per-query timeout in milliseconds; `0` or omitted uses the default of 10000 (10 seconds)." + } + } + }, + "DSPayload": { + "type": "object", + "description": "Type-specific datasource configuration. Include only the block matching `type_ident`.", + "properties": { + "prometheus": { + "$ref": "#/components/schemas/DSPrometheusConfig" + }, + "loki": { + "$ref": "#/components/schemas/DSLokiConfig" + }, + "mysql": { + "$ref": "#/components/schemas/DSMySQLConfig" + }, + "oracle": { + "$ref": "#/components/schemas/DSOracleConfig" + }, + "postgres": { + "$ref": "#/components/schemas/DSPostgresConfig" + }, + "clickhouse": { + "$ref": "#/components/schemas/DSClickHouseConfig" + }, + "elasticsearch": { + "$ref": "#/components/schemas/DSElasticSearchConfig" + }, + "sls": { + "$ref": "#/components/schemas/DSSLSConfig" + }, + "victorialogs": { + "$ref": "#/components/schemas/DSVictoriaLogsConfig" + }, + "tencent_cls": { + "$ref": "#/components/schemas/DSTencentCLSConfig", + "description": "Tencent CLS credentials. Required when `type_ident` is `tencent_cls`." + }, + "kafka": { + "$ref": "#/components/schemas/DSKafkaConfig", + "x-flashduty-preserve-absence": true + }, + "mongodb_mongod": { + "$ref": "#/components/schemas/DSMongoDBConfig", + "x-flashduty-preserve-absence": true + }, + "mongodb_mongos": { + "$ref": "#/components/schemas/DSMongoDBConfig", + "x-flashduty-preserve-absence": true + }, + "redis_node": { + "$ref": "#/components/schemas/DSRedisNodeConfig", + "x-flashduty-preserve-absence": true + }, + "redis_sentinel": { + "$ref": "#/components/schemas/DSRedisSentinelConfig", + "x-flashduty-preserve-absence": true + } + } + }, + "DSPostgresConfig": { + "type": "object", + "description": "PostgreSQL datasource configuration.", + "properties": { + "username": { + "type": "string", + "description": "PostgreSQL authentication username." + }, + "password": { + "type": "string", + "description": "PostgreSQL authentication password." + }, + "open_conns": { + "type": "integer", + "description": "Maximum number of open connections in the pool; `0` or omitted uses the default of 32." + }, + "idle_conns": { + "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", + "description": "Maximum connection lifetime in seconds; `0` or omitted uses the default of 600 (10 minutes)." + }, + "timeout_mills": { + "type": "integer", + "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", + "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", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + }, + "tls_key": { + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + } + } + }, + "DSPrometheusConfig": { + "type": "object", + "description": "Prometheus datasource configuration. TLS fields are inherited from TLSClientConfig.", + "properties": { + "basic_auth_enabled": { + "type": "boolean", + "description": "Enable HTTP Basic Auth." + }, + "basic_auth_username": { + "type": "string", + "description": "Basic auth username." + }, + "basic_auth_password": { + "type": "string", + "description": "Basic auth password." + }, + "headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Custom HTTP headers in `Key: Value` format." + }, + "params": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Custom query parameters in `key=value` format." + }, + "tls_ca": { + "type": "string", + "description": "PEM-encoded CA certificate used to verify the server certificate." + }, + "tls_cert": { + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + }, + "tls_key": { + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + }, + "tls_server_name": { + "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", + "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", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + } + } + }, + "DSSLSConfig": { + "type": "object", + "description": "Alibaba Cloud SLS datasource configuration.", + "properties": { + "access_key_id": { + "type": "string", + "description": "Alibaba Cloud Access Key ID." + }, + "access_key_secret": { + "type": "string", + "description": "Alibaba Cloud Access Key Secret." + }, + "headers": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Custom HTTP headers." + } + } + }, + "DSType": { + "type": "object", + "description": "A datasource type definition usable by alert rules.", + "required": [ + "id", + "name", + "ident", + "account_id", + "weight" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "ID of the datasource type record." + }, + "name": { + "type": "string", + "description": "Display name, e.g. `Prometheus`." + }, + "ident": { + "type": "string", + "description": "Identifier used as the `ds_type` of rules, e.g. `prometheus`." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "Owning account ID. `0` for global types." + }, + "weight": { + "type": "integer", + "description": "Display order weight; higher appears first." + } + } + }, + "DSVictoriaLogsConfig": { + "type": "object", + "description": "VictoriaLogs datasource configuration. TLS fields are inherited from TLSClientConfig.", + "properties": { + "basic_auth_enabled": { + "type": "boolean", + "description": "Whether HTTP Basic Auth is enabled; when `false`, `basic_auth_username`/`basic_auth_password` are ignored." + }, + "basic_auth_username": { + "type": "string", + "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." + }, + "basic_auth_password": { + "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", + "description": "PEM-encoded CA certificate used to verify the server certificate." + }, + "tls_cert": { + "type": "string", + "description": "PEM-encoded client certificate for mutual TLS; must be configured together with `tls_key`." + }, + "tls_key": { + "type": "string", + "description": "PEM-encoded client private key; must be configured together with `tls_cert`." + }, + "tls_skip_verify": { + "type": "boolean", + "description": "Whether to skip server certificate verification (insecure, for self-signed setups only)." + }, + "tls_server_name": { + "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", + "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", + "description": "Maximum TLS version, one of `1.0`, `1.1`, `1.2`, `1.3`; empty means no constraint." + } + } + }, + "DataSourceItem": { + "type": "object", + "description": "A monitoring datasource.", + "required": [ + "id", + "account_id", + "type_ident", + "name", + "enabled", + "note", + "address", + "edge_cluster_name", + "updated_at", + "payload", + "alerting_enabled" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "Unique datasource ID." + }, + "account_id": { + "type": "integer", + "format": "uint64", + "description": "Account ID." + }, + "type_ident": { + "type": "string", + "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + }, + "name": { + "type": "string", + "description": "Datasource display name." + }, + "enabled": { + "type": "boolean", + "description": "Whether business execution is enabled. Disabled datasources reject business queries and tools; enabling does not change alerting_enabled." + }, + "note": { + "type": "string", + "description": "Optional description." + }, + "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. Redis/MongoDB diagnostic types: one host:port, bracket IPv6; no URI, userinfo or query. Kafka: 1–32 unique comma-separated host:port bootstrap addresses; payload has no broker list. At most 4096 characters after normalization.", + "maxLength": 4096 + }, + "payload": { + "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. For diagnostic types, password and Kafka tls_key are omitted from responses unless they are ${env:...} references. On update, omit those fields to preserve stored secrets; explicitly send an empty string to clear. Other configuration fields retain their existing behavior." + }, + "edge_cluster_name": { + "type": "string", + "description": "Monitors edge cluster name responsible for evaluating rules using this datasource." + }, + "updated_at": { + "type": "integer", + "format": "int64", + "description": "Last update timestamp, Unix epoch seconds." + }, + "alerting_enabled": { + "description": "Whether alert evaluation is allowed. Alerting also requires enabled=true and an alerting-capable type. Always false for diagnostic-only types; false does not block non-alerting queries or tools.", + "type": "boolean" + } + } + }, + "DataSourceListRequest": { + "type": "object", + "description": "Filter parameters for listing datasources.", + "properties": { + "type": { + "type": "string", + "description": "Datasource type identifier. Omit to return all types. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + } + } + }, + "DataSourceListResponse": { + "type": "array", + "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" + } + }, + "DataSourceUpsertRequest": { + "type": "object", + "description": "Request body for creating or updating a datasource. `id` is required only for update. `address` is required for all types except Elasticsearch with `deployment=cloud`.", + "required": [ + "type_ident", + "name", + "edge_cluster_name", + "payload" + ], + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "Datasource ID. Required for update; omit for create." + }, + "type_ident": { + "type": "string", + "description": "Datasource type identifier. Allowed: `prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + }, + "name": { + "type": "string", + "description": "Datasource display name. This is the name referenced as `ds_name` in query and diagnose APIs." + }, + "note": { + "type": "string", + "description": "Optional description." + }, + "address": { + "type": "string", + "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). Redis/MongoDB diagnostic types: one host:port, bracket IPv6; no URI, userinfo or query. Kafka: 1–32 unique comma-separated host:port bootstrap addresses; payload has no broker list. At most 4096 characters after normalization.", + "maxLength": 4096 + }, + "payload": { + "$ref": "#/components/schemas/DSPayload", + "description": "Type-specific configuration block. Must include the key matching `type_ident`. For diagnostic types, password and Kafka tls_key are omitted from responses unless they are ${env:...} references. On update, omit those fields to preserve stored secrets; explicitly send an empty string to clear. Other configuration fields retain their existing behavior." + }, + "edge_cluster_name": { + "type": "string", + "description": "Monitors edge cluster name responsible for evaluating rules using this datasource." + }, + "enabled": { + "type": "boolean", + "description": "Whether business execution is enabled. Omitted on create: true; omitted on update: preserve the current value. Explicit false disables execution; null is invalid. Does not change alerting_enabled.", + "x-flashduty-preserve-absence": true + }, + "alerting_enabled": { + "description": "Whether this datasource may evaluate alerts. Omitted on create: true for alerting types, false for diagnostic-only types; omitted on update: preserve current value. null is invalid. redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka reject true. Disabling is rejected with conflict when enabled rules reference the datasource.", + "type": "boolean", + "x-flashduty-preserve-absence": true + } + } + }, + "DutyError": { + "type": "object", + "description": "Error payload inside the response envelope. Present only on non-2xx responses.", + "properties": { + "code": { + "$ref": "#/components/schemas/ErrorCode" + }, + "message": { + "type": "string", + "description": "Human-readable error message, localized by the caller's Accept-Language. May contain field names, IDs, or other context from the failing request.", + "example": "The specified parameter template_id is not valid." + }, + "reason": { + "description": "Optional machine-readable rejection reason, including datasource tool failures. Inspect alongside HTTP status and code.", + "type": "string", + "x-flashduty-preserve-absence": true + } + }, + "required": [ + "code", + "message" + ] + }, + "EmptyResponse": { + "type": "object", + "description": "Empty response body. The server returns `data: null` on success.", + "properties": {} + }, + "EnabledTime": { + "type": "object", + "description": "Time window in which the rule is active.", + "properties": { + "days": { + "type": "array", + "items": { + "type": "integer" + }, + "description": "Days of week, 0 = Sunday." + }, + "stime": { + "type": "string", + "description": "Start time, e.g. `09:00`." + }, + "etime": { + "type": "string", + "description": "End time, e.g. `18:00`." + } + } + }, + "ErrorCode": { + "type": "string", + "description": "Flashduty error code enum. Every failed API response sets `error.code` to one of these stable wire strings. HTTP status is informational — the authoritative signal is the enum value.\n\n| Code | HTTP | Meaning |\n|---|---|---|\n| `OK` | 200 | Reserved — not returned on real errors. |\n| `InvalidParameter` | 400 | A required parameter is missing or failed validation. |\n| `BadRequest` | 400 | Generic 400 used when no more specific code fits. |\n| `InvalidContentType` | 400 | The `Content-Type` header is not `application/json`. |\n| `ResourceNotFound` | 400 | The referenced resource does not exist. Note: returned as HTTP 400, not 404 (historical choice). |\n| `NoLicense` | 400 | The feature is license-gated and no active license was found. |\n| `ReferenceExist` | 400 | Deletion blocked — other entities still reference this resource. |\n| `Unauthorized` | 401 | `app_key` is missing, invalid, or expired. |\n| `BalanceNotEnough` | 402 | Billing-gated operation with insufficient account balance. |\n| `AccessDenied` | 403 | Authenticated but lacking the permission required for this operation. |\n| `RouteNotFound` | 404 | The request URL path is not a known route. |\n| `MethodNotAllowed` | 405 | The HTTP method is not allowed on this otherwise-known path. |\n| `UndonedOrderExist` | 409 | An outstanding billing order blocks this new one. Wait and retry. |\n| `RequestLocked` | 423 | Operation temporarily locked due to repeated failures. |\n| `EntityTooLarge` | 413 | Request body exceeds the configured max size. |\n| `RequestTooFrequently` | 429 | Rate limit hit — API-global, per-account, or per-integration. |\n| `RequestVerifyRequired` | 428 | Second-factor verification required but not supplied. |\n| `DangerousOperation` | 428 | High-risk operation requires MFA verification. |\n| `InternalError` | 500 | Unhandled server-side error. Include `request_id` in the bug report. |\n| `ServiceUnavailable` | 503 | A backend dependency is unavailable. Try again later. |", + "enum": [ + "OK", + "InvalidParameter", + "BadRequest", + "InvalidContentType", + "ResourceNotFound", + "NoLicense", + "ReferenceExist", + "Unauthorized", + "BalanceNotEnough", + "AccessDenied", + "RouteNotFound", + "MethodNotAllowed", + "UndonedOrderExist", + "RequestLocked", + "EntityTooLarge", + "RequestTooFrequently", + "RequestVerifyRequired", + "DangerousOperation", + "InternalError", + "ServiceUnavailable" + ], + "x-enumDescriptions": { + "OK": "Reserved — not returned on real errors.", + "InvalidParameter": "A required parameter is missing or failed validation.", + "BadRequest": "Generic 400 used when no more specific code fits.", + "InvalidContentType": "The `Content-Type` header is not `application/json`.", + "ResourceNotFound": "The referenced resource does not exist. Note: returned as HTTP 400, not 404 (historical choice).", + "NoLicense": "The feature is license-gated and no active license was found.", + "ReferenceExist": "Deletion blocked — other entities still reference this resource.", + "Unauthorized": "`app_key` is missing, invalid, or expired.", + "BalanceNotEnough": "Billing-gated operation with insufficient account balance.", + "AccessDenied": "Authenticated but lacking the permission required for this operation.", + "RouteNotFound": "The request URL path is not a known route.", + "MethodNotAllowed": "The HTTP method is not allowed on this otherwise-known path.", + "UndonedOrderExist": "An outstanding billing order blocks this new one. Wait and retry.", + "RequestLocked": "Operation temporarily locked due to repeated failures.", + "EntityTooLarge": "Request body exceeds the configured max size.", + "RequestTooFrequently": "Rate limit hit — API-global, per-account, or per-integration.", + "RequestVerifyRequired": "Second-factor verification required but not supplied.", + "DangerousOperation": "High-risk operation requires MFA verification.", + "InternalError": "Unhandled server-side error. Include `request_id` in the bug report.", + "ServiceUnavailable": "A backend dependency is unavailable. Try again later." + }, + "example": "InvalidParameter" + }, + "ErrorResponse": { + "type": "object", + "description": "Response envelope for errors. `error` is required; `data` is absent.", + "properties": { + "request_id": { + "type": "string", + "example": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", + "description": "Unique trace ID of this request; include it when reporting issues so logs can be located." + }, + "error": { + "$ref": "#/components/schemas/DutyError" + } + }, + "required": [ + "request_id", + "error" + ] + }, + "IDRequest": { + "type": "object", + "required": [ + "id" + ], + "description": "Request with a single numeric ID.", + "properties": { + "id": { + "type": "integer", + "format": "uint64", + "description": "Numeric ID of the target resource; the exact meaning depends on the API being called (e.g. datasource ID, ruleset ID)." + } + } + }, + "NameMessage": { + "type": "object", + "description": "Per-item result for batch rule operations.", + "required": [ + "name", + "message" + ], + "properties": { + "name": { + "type": "string", + "description": "Rule name." + }, + "message": { + "type": "string", + "description": "Empty on success, error message on failure." + } + } + }, + "RuleAuditListResponse": { + "type": "array", + "description": "Audit records for a rule, ordered by creation time descending. The `content` field is omitted.", + "items": { + "$ref": "#/components/schemas/AlertRuleAudit" + } + }, + "RuleBasicListResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AlertRuleBasic" + }, + "description": "List of alert rules (basic info)." + }, + "RuleConfigs": { + "type": "object", + "description": "Rule evaluation configuration.", + "properties": { + "queries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Query identifier (letter, e.g. `A`). The name `R` is reserved and must not be used." + }, + "expr": { + "type": "string", + "description": "Query expression." + }, + "label_fields": { + "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 `.