diff --git a/.github/workflows/openapi-lint.yml b/.github/workflows/openapi-lint.yml index affbe288e..4a556efb3 100644 --- a/.github/workflows/openapi-lint.yml +++ b/.github/workflows/openapi-lint.yml @@ -1,9 +1,11 @@ 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. +# properties, epoch time fields without Unix/timestamp wording, enums whose +# values are not explained in the description, `required` entries that name +# undeclared properties, operations without examples or a 403 response, +# examples that do not match their schema, and over-long operation +# descriptions. See scripts/lint_openapi.py for the rules. on: pull_request: diff --git a/api-reference/monitors.openapi.en.json b/api-reference/monitors.openapi.en.json index c64821fe2..de1407dba 100644 --- a/api-reference/monitors.openapi.en.json +++ b/api-reference/monitors.openapi.en.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "Flashduty Open API", - "description": "Public HTTP API for the Flashduty incident management platform — incidents, notification templates, channels, schedules, monitors, RUM, and platform administration. Every operation is authenticated with an `app_key` query parameter issued from the Flashduty console under Account → APP Keys. Responses follow a uniform envelope: `{ request_id, data }` on success, `{ request_id, error }` on failure.", + "description": "Public HTTP API for the Flashduty incident management platform — incidents, notification templates, channels, schedules, monitors, RUM, and platform administration. Every operation is authenticated with an `app_key` query parameter created in the Flashduty console under My → APP Key (or sent in the `Fd-App-Key` header). Responses follow a uniform envelope: `{ request_id, data }` on success, `{ request_id, error }` on failure.", "version": "1.0.0" }, "servers": [ @@ -52,7 +52,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 Read** (`monit`) |\n\n## Usage\n\n- Each item is a historical snapshot: `num` is the total rule count at the given `clock` (Unix epoch seconds).", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Monits Overview Read** (`monit`) |\n\n## Usage\n\n- Each item is a historical snapshot: `num` is the total number of alert rules in the account (enabled and disabled) at `clock` (Unix timestamp in seconds).\n- A snapshot is recorded roughly every 12 hours (an hourly job adds one when none exists in the last 12 hours). All snapshots are returned oldest first; the array is empty until the first snapshot is recorded.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-counter-total", "metadata": { "sidebarTitle": "Get rule counter time series" @@ -83,7 +83,13 @@ "data": [ { "id": 1, - "account_id": 10023, + "account_id": 888, + "num": 48, + "clock": 1711956000 + }, + { + "id": 2, + "account_id": 888, "num": 50, "clock": 1712000000 } @@ -98,6 +104,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -122,12 +131,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. Supports diagnostic types redis_node, redis_sentinel, mongodb_mongod, mongodb_mongos and kafka; enabled and alerting_enabled are independent.", + "description": "Create a monitoring datasource of one of 15 supported types and bind it to a Monitors edge cluster.", "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`, `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.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 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`. The last five (`redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`) are diagnostic-only: they cannot evaluate alerts, so `alerting_enabled` must not be `true`.\n- `name` must be unique within the account across all types; a duplicate fails with `InvalidParameter`.\n- `edge_cluster_name` must be an existing Monitors edge cluster of the account; that cluster evaluates rules and runs queries for the datasource.\n- Put the type-specific settings in `payload.`. For `elasticsearch`, `payload.elasticsearch.deployment` is required (`cloud` or `self-managed`). `tencent_cls` requires every edge instance in the cluster to run Monitors edge v0.66.0 or later.\n- Omitted `enabled` defaults to `true`; omitted `alerting_enabled` defaults to `true` for alerting types and `false` for diagnostic-only types. Explicit `null` for either is rejected.\n- `manage_team_id` and `readonly_team_ids` restrict who can manage or query the datasource; omit both to leave it open to every member.\n- Responses return credentials of non-diagnostic types (for example Prometheus Basic Auth passwords) as stored. Diagnostic passwords and Kafka private keys are returned only when they are `${env:NAME}` references. Treat responses as sensitive.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-create", "metadata": { "sidebarTitle": "Create datasource" @@ -157,12 +166,26 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "id": 10, + "account_id": 10023, "type_ident": "prometheus", "name": "Prometheus Prod", "enabled": true, + "note": "Production Prometheus", + "address": "http://prometheus.example.com:9090", + "payload": { + "prometheus": { + "basic_auth_enabled": false, + "basic_auth_username": "", + "basic_auth_password": "", + "tls_skip_verify": false + } + }, "edge_cluster_name": "default", "updated_at": 1712000000, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001 } } } @@ -174,6 +197,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -209,12 +235,12 @@ "post": { "operationId": "monit-datasource-write-update", "summary": "Update datasource", - "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.", + "description": "Update a datasource by ID, replacing its name, note, address, payload and edge cluster.", "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. 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.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Datasources Manage** (`monit`) |\n\n## Usage\n\n- This is a full replace, not a patch: send `type_ident`, `name`, `edge_cluster_name`, `payload` and (except for Elasticsearch `cloud`) `address` on every call. `note`, `address` and `payload` overwrite the stored values, so an omitted `note` is cleared.\n- Omitting `enabled`, `alerting_enabled`, `manage_team_id` or `readonly_team_ids` keeps the current value. `null` for `enabled` or `alerting_enabled` is rejected; `null` for the two team fields clears them.\n- Secrets: for the diagnostic types, omit the password (and the Kafka `tls_key`) to keep the stored value or send an empty string to clear it. For `tencent_cls`, an omitted or empty `secret_key` keeps the stored key. Other types need their credentials resent.\n- Setting `enabled` or `alerting_enabled` to `false`, or changing `type_ident` or `edge_cluster_name`, closes open alerts of the rules that use this datasource. Renaming it closes open alerts of rules whose `ds_list` name pattern no longer matches the new name.\n- Turning `alerting_enabled` off fails with HTTP 409 `UndonedOrderExist` while an enabled alert rule still selects the datasource.\n- Only the account owner, Admin members, the creator and members of the managing team can update a datasource (anyone with the permission when no managing team is set); others get `AccessDenied`. An unknown ID, or one in another account, returns `ResourceNotFound`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-update", "metadata": { "sidebarTitle": "Update datasource" @@ -244,12 +270,26 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "id": 10, + "account_id": 10023, "type_ident": "prometheus", "name": "Prometheus Prod v2", "enabled": true, + "note": "Updated", + "address": "http://prometheus-v2.example.com:9090", + "payload": { + "prometheus": { + "basic_auth_enabled": false, + "basic_auth_username": "", + "basic_auth_password": "", + "tls_skip_verify": false + } + }, "edge_cluster_name": "default", "updated_at": 1712100000, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001 } } } @@ -261,6 +301,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -302,7 +345,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- 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.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `dest_folder_id` must be an existing folder that the caller must be able to manage the folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor); otherwise the whole call fails with `AccessDenied` and nothing is moved.\n- The result has one entry per requested ID, in request order. A moved rule's `message` is a localized success text (`Move successfully` / `移动成功`); a rule that is not moved stays in its folder and its `message` carries the error.\n- A rule is not moved when a rule with the same name already exists in the destination folder, when the caller cannot manage its current folder, or when the ID does not exist (its `name` is then `id: `).\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" @@ -333,7 +376,11 @@ "data": [ { "name": "CPU High", - "message": "" + "message": "Move successfully" + }, + { + "name": "Disk High", + "message": "alert rule name already exists in this folder" } ] } @@ -346,6 +393,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -376,12 +426,12 @@ "post": { "operationId": "monit-rule-read-audit-detail", "summary": "Get rule audit snapshot", - "description": "Return the audit record (including the `content` field, a JSON string of the rule snapshot at that point in time).", + "description": "Return one audit record of an alert rule, including the rule snapshot stored in `content`.", "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 Read** (`monit`) |\n\n## Usage\n\n- Pass the audit record `id` (not the rule `id`) from `POST /monit/rule/audits`.\n- `content` is a JSON string — parse it to get the full rule snapshot.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Pass the audit record `id` (not the rule `id`) from `POST /monit/rule/audits`. An unknown ID returns `InvalidParameter` (`alert rule audit not found`).\n- `content` is a JSON string — parse it to get the rule snapshot; its shape depends on the operation that wrote the record (see `content` below).\n- To read a record, the caller must be able to manage the rule's folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor); otherwise the call returns `AccessDenied`. Records of a deleted rule can no longer be read: the call returns `InvalidParameter` (`alert rule not found`).", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-audit-detail", "metadata": { "sidebarTitle": "Get rule audit snapshot" @@ -411,13 +461,13 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "id": 9001, - "account_id": 10023, + "account_id": 888, "alert_rule_id": 50001, "action": "update", - "content": "{\"id\":50001,\"name\":\"CPU High\"}", - "creator_id": 80011, - "creator_name": "Alice", - "created_at": 1712000000 + "content": "{\"id\":50001,\"account_id\":888,\"folder_id\":100,\"name\":\"CPU High\",\"enabled\":true,\"updated_at\":1712003600}", + "creator_id": 66, + "creator_name": "zhangsan", + "created_at": 1712003600 } } } @@ -429,6 +479,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -455,12 +508,12 @@ "post": { "operationId": "monit-datasource-write-delete", "summary": "Delete datasource", - "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.", + "description": "Delete a datasource by ID; alert rules that reference it are not blocked.", "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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Datasources Manage** (`monit`) |\n\n## Usage\n\n- Alert rules that reference the datasource are not blocked or edited; their open alerts on it are closed automatically.\n- Deleting an ID that does not exist succeeds as a no-op; an ID in another account returns `ResourceNotFound`.\n- Only the account owner, Admin members, the creator and members of the managing team can delete a datasource (anyone with the permission when no managing team is set); others get `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-write-delete", "metadata": { "sidebarTitle": "Delete datasource" @@ -499,6 +552,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -530,7 +586,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **5 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 | **100 requests/minute**; **5 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- IDs are processed in order and the call stops at the first error; rules deleted before the error stay deleted, so fix the cause and re-send the remaining IDs.\n- IDs that do not exist are skipped without error. Each deleted rule's active alerts are cleared.\n- `ids` must contain at least one ID. For every rule, the caller must be able to manage its folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor); otherwise the call returns `AccessDenied`.\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-delete-batch", "metadata": { "sidebarTitle": "Batch delete alert rules" @@ -569,6 +625,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -603,7 +662,7 @@ "Monitors/Data sources" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- The datasource identified by `id` must be of type `sls`.\n- Use `query` to filter projects by name prefix. Use `offset` and `size` for pagination.", + "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- The datasource identified by `id` must be of type `sls`; other types fail with `InvalidParameter`.\n- Use `query` to filter the project list and `offset` and `size` to paginate; `count` is the number of projects in the page and `total` the number matching the filter.\n- The request is relayed to the Monitors edge cluster of the datasource, which calls Alibaba Cloud with the stored credentials; it times out after 30 seconds. Fails with `InvalidParameter` when no edge instance of that cluster is online, and with HTTP 503 `ServiceUnavailable` when the edge version does not support metadata discovery.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-sls-projects", "metadata": { "sidebarTitle": "List SLS projects" @@ -665,6 +724,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -699,7 +761,7 @@ "Monitors/Data sources" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- The datasource identified by `id` must be of type `sls`.\n- Supply `project` to select the SLS project whose logstores to list.", + "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- The datasource identified by `id` must be of type `sls`; other types fail with `InvalidParameter`.\n- Supply `project` to select the SLS project whose logstores to list; use `offset` and `size` to paginate. The response is a plain array of logstore names.\n- The request is relayed to the Monitors edge cluster of the datasource, which calls Alibaba Cloud with the stored credentials; it times out after 30 seconds. Fails with `InvalidParameter` when no edge instance of that cluster is online, and with HTTP 503 `ServiceUnavailable` when the edge version does not support metadata discovery.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-sls-logstores", "metadata": { "sidebarTitle": "List SLS logstores" @@ -741,6 +803,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -770,12 +835,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 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.", + "description": "Return one datasource by ID, including its full `payload` configuration.", "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\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.", + "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- Requires manage access to the datasource (see `manage_team_id`); members who can only query it get `AccessDenied`. Use `/monit/datasource/list` for the datasources you can query.\n- The response is sensitive: `payload` holds connection settings, and credentials of non-diagnostic types are returned as stored. Diagnostic passwords and Kafka private keys are returned only when they are `${env:NAME}` references; `tencent_cls` `secret_key` is returned as an empty string unless it is a `${env:NAME}` reference.\n- An unknown ID, or one in another account, returns `ResourceNotFound`.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-info", "metadata": { "sidebarTitle": "Get datasource detail" @@ -821,7 +886,10 @@ }, "edge_cluster_name": "default", "updated_at": 1712000000, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001 } } } @@ -833,6 +901,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -864,7 +935,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 Read** (`monit`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Records are ordered newest first and omit `content`; read one snapshot with `POST /monit/rule/audit/detail`.\n- A record is written on every create, full update, field update and move. Deleting a rule writes no record, and the history of a deleted rule can no longer be listed: the call returns `InvalidParameter` (`alert rule not found`).\n- The caller must be able to manage the rule's folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor); otherwise the call returns `AccessDenied`.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-audits", "metadata": { "sidebarTitle": "List rule change history" @@ -895,11 +966,20 @@ "data": [ { "id": 9001, - "account_id": 10023, + "account_id": 888, "alert_rule_id": 50001, "action": "update", - "creator_id": 80011, - "creator_name": "Alice", + "creator_id": 66, + "creator_name": "zhangsan", + "created_at": 1712003600 + }, + { + "id": 8990, + "account_id": 888, + "alert_rule_id": 50001, + "action": "create", + "creator_id": 66, + "creator_name": "zhangsan", "created_at": 1712000000 } ] @@ -913,6 +993,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -944,7 +1027,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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- The rule's active alerts are cleared as part of the deletion.\n- Deleting an ID that does not exist succeeds with an empty `data`, so retries are safe.\n- The caller must be able to manage the rule's folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor); otherwise the call returns `AccessDenied`.\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-delete", "metadata": { "sidebarTitle": "Delete alert rule" @@ -983,6 +1066,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1009,12 +1095,12 @@ "post": { "operationId": "monit-rule-read-list", "summary": "List alert rules", - "description": "Return the basic information of all alert rules in a folder. For full rule details, call `POST /monit/rule/v2/info`.", + "description": "Return basic information for the alert rules in a folder; call `POST /monit/rule/v2/info` for full details.", "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 Read** (`monit`) |\n\n## Usage\n\n- Set `folder_id` to `0` to list all rules across all folders visible to the current user.\n- The `triggered` field indicates whether the rule has any currently active alerts.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Read** or **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `folder_id` must be an existing folder: `0` or an unknown ID returns `InvalidParameter`, and a folder the caller cannot manage (account owner or admin, creator of the folder or an ancestor, or member of the team bound to it or an ancestor) returns `AccessDenied`. There is no account-wide listing.\n- By default only the rules directly in the folder are returned, sorted by name, with `active_alert_count` and `runtime_state` filled.\n- With `include_descendants: true` the call searches the folder and all its descendant folders and returns at most `limit` rules sorted by name; only `id`, `folder_id` and `name` are filled and the other fields carry zero values (`labels` is `null`, `runtime_state` is omitted).\n- `triggered` is `true` exactly when `active_alert_count > 0`.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-list", "metadata": { "sidebarTitle": "List alert rules" @@ -1045,12 +1131,25 @@ "data": [ { "id": 50001, + "account_id": 888, "folder_id": 100, "name": "CPU High", + "labels": { + "team": "sre" + }, "ds_type": "prometheus", "enabled": true, - "triggered": true, + "debug_log_enabled": false, + "cron_pattern": "0 * * * * *", + "timezone": "Asia/Shanghai", + "delay_seconds": 0, + "creator_id": 66, + "creator_name": "zhangsan", + "updater_id": 66, + "updater_name": "zhangsan", "created_at": 1710000000, + "updated_at": 1712000000, + "triggered": true, "active_alert_count": 2, "runtime_state": "normal" } @@ -1065,6 +1164,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1091,12 +1193,12 @@ "post": { "operationId": "monit-datasource-read-list", "summary": "List datasources", - "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.", + "description": "List the account's datasources that the caller can query, optionally filtered by type or exact name.", "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.\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.", + "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` and `name` to return every datasource you can query; `type` and `name` are exact-match filters. An unrecognized `type` returns an empty array. The result is not paginated.\n- Only datasources the caller can query are returned (see `readonly_team_ids`); each item carries `my_perm` (`manage` or `readonly`).\n- `payload` is always `null` in list items. Use `/monit/datasource/info` to read the configuration of a datasource you can manage.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-read-list", "metadata": { "sidebarTitle": "List datasources" @@ -1133,10 +1235,14 @@ "enabled": true, "note": "Production Prometheus", "address": "http://prometheus.example.com:9090", + "payload": null, "edge_cluster_name": "default", "updated_at": 1712000000, - "payload": null, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001, + "my_perm": "manage" } ] } @@ -1149,6 +1255,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1175,12 +1284,12 @@ "post": { "operationId": "monit-rule-write-fields-update", "summary": "Batch update rule fields", - "description": "Update specific fields across multiple alert rules at once. Only the fields listed in `fields` are applied.", + "description": "Update the fields listed in `fields` on multiple alert rules in one call.", "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- Include the field names you want to update in the `fields` array, e.g. `[\"enabled\", \"channel_ids\"]`.\n- Only the specified fields are updated; others are left unchanged.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- Each listed field takes the value of the same-named request field; a listed field whose value is omitted is set to its zero value (for example, listing `labels` without `labels` or `labels_patch` removes all labels). Unlisted fields keep their current values.\n- An unknown name in `fields`, a `labels_patch` / `annotations_patch` whose field is not listed in `fields`, or sending `labels` together with `labels_patch` (or `annotations` with `annotations_patch`) fails the whole call with `InvalidParameter`.\n- Rules are updated one by one and the result has one entry per ID: `message` is empty on success, otherwise it carries that rule's error (validation failure, no access to its folder, or an unknown ID, whose `name` is then `id: `).\n- Setting `enabled` to `false` clears the rules' active alerts. Unless the call only disables rules (`fields` is exactly `[\"enabled\"]` with `enabled: false`), it fails with `AccessDenied` when the account exceeds its alert rule license limit, and non-admin callers need read-only access to every datasource each rule selects.\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-fields-update", "metadata": { "sidebarTitle": "Batch update rule fields" @@ -1228,6 +1337,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1261,12 +1373,12 @@ "post": { "operationId": "monit-rule-read-counter-channel", "summary": "Get rule counts by channel", - "description": "Return an object mapping channel name to the number of rules routing alerts to that channel. If a channel name cannot be resolved, the channel ID (as a string) is used as the key.", + "description": "Return how many alert rules route alerts to each collaboration space, keyed by space name.", "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 Read** (`monit`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Monits Overview Read** (`monit`) |\n\n## Usage\n\n- Only rules with a non-empty `channel_ids` are counted; a rule routed to several spaces is counted once under each of them.\n- When a space ID cannot be resolved to a name, the ID (as a string) is used as the key. Spaces that share the same name are merged into one key.\n- Returns an empty object `{}` when no rule routes to a space.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-counter-channel", "metadata": { "sidebarTitle": "Get rule counts by channel" @@ -1307,6 +1419,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1336,7 +1451,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 Read** (`monit`) |\n\n## Usage\n\n- `id` is required and must not be `0`; otherwise the call returns `InvalidParameter`.\n- A missing rule returns `InvalidParameter` (`alert rule not found`).", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Read** or **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `id` is required and must not be `0`; otherwise the call returns `InvalidParameter`.\n- A missing rule, or a rule of another account, returns `InvalidParameter` (`alert rule not found`).\n- No folder-level check applies: any caller with the permission above can read every rule in the account.", "href": "/en/api-reference/monitors/alert-rules/monit-rule-read-info-v2", "metadata": { "sidebarTitle": "Get alert rule detail (V2)" @@ -1378,6 +1493,7 @@ "enabled": true, "debug_log_enabled": false, "rule_configs": { + "relate_queries": [], "queries": [ { "name": "A", @@ -1438,6 +1554,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1469,7 +1588,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `name`, `ds_type`, `enabled`, `cron_pattern`, and `rule_configs.queries` are required; either `ds_list` (supports wildcards) or `ds_ids` must be non-empty.\n- `enabled` must be passed explicitly (including `false`); omitting it returns `InvalidParameter`.\n- `id`, `account_id`, `creator_*`, `updater_*`, `created_at`, and `updated_at` are assigned by the server; client-supplied values are ignored.\n- `name` must be unique within `folder_id`; a duplicate returns `InvalidParameter`.\n- `channel_ids` can be empty; alerts will then route through the global integration.\n- The request body tolerates additional unknown fields (forward compatibility); they are ignored.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `folder_id`, `name`, `ds_type`, `enabled`, `cron_pattern` and `rule_configs.queries` are required, and at least one of `ds_list` (wildcards supported) or `ds_ids` must be non-empty.\n- `enabled` must be passed explicitly (including `false`); omitting it returns `InvalidParameter`.\n- `folder_id` must be an existing folder (otherwise `InvalidParameter`) and the caller must be able to manage the folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor) (otherwise `AccessDenied`).\n- `name` must be unique within `folder_id`; a duplicate returns `InvalidParameter`.\n- When `enabled` is `true`, `ds_type` must be a datasource type that supports alerting and every ID in `ds_ids` must be an enabled datasource with alerting turned on; otherwise the call returns `InvalidParameter`.\n- Callers other than the account owner or admins need read-only access to every datasource listed in `ds_ids` or currently matched by `ds_list`; otherwise the call returns `AccessDenied` (`no permission to reference datasource \"\"`).\n- The call fails with `AccessDenied` when creating the rule would exceed the account's alert rule license limit.\n- `id`, `account_id`, `creator_*`, `updater_*`, `created_at`, and `updated_at` are assigned by the server; client-supplied values are ignored.\n- `channel_ids` can be empty; alerts will then route through the global integration.\n- The request body may not exceed 1 MiB; a larger body returns HTTP 413 (`EntityTooLarge`). Additional unknown fields are ignored (forward compatibility).\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-v2", "metadata": { "sidebarTitle": "Create alert rule (V2)" @@ -1511,6 +1630,7 @@ "enabled": true, "debug_log_enabled": false, "rule_configs": { + "relate_queries": [], "queries": [ { "name": "A", @@ -1571,6 +1691,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1629,7 +1752,7 @@ "Monitors/Alert rules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `id` is required and the rule must already exist; otherwise the call returns `InvalidParameter`.\n- This is a full-field replacement: except for the cases below, fields you omit are stored as zero values. Fetch the full configuration via `/monit/rule/v2/info` before modifying it.\n- `enabled` must be passed explicitly (including `false`); omitting it returns `InvalidParameter`. Setting it to `false` clears the rule's active alerts.\n- `investigation_targets` is the exception: omit it to keep the current value, pass `[]` to clear, or pass a value to replace it entirely.\n- `folder_id` cannot be changed through this operation; use `/monit/rule/move` to move the rule to another folder.\n- `account_id`, `creator_*`, `updater_*`, `created_at`, and `updated_at` are maintained by the server; client-supplied values are ignored.\n- `name` must be unique within `folder_id`; a duplicate returns `InvalidParameter`.\n- The request body tolerates additional unknown fields (forward compatibility); they are ignored.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** (`monit`) |\n\n## Usage\n\n- `id` is required and the rule must already exist; otherwise the call returns `InvalidParameter`.\n- This is a full-field replacement: except for the cases below, fields you omit are stored as zero values (then normalized, e.g. `repeat_interval` becomes 3600). Fetch the full configuration via `/monit/rule/v2/info` before modifying it.\n- `enabled` must be passed explicitly (including `false`); omitting it returns `InvalidParameter`. Setting it to `false` clears the rule's active alerts.\n- `investigation_targets` is the exception: omit it to keep the current value, pass `[]` to clear, or pass a value to replace it entirely.\n- `folder_id` cannot be changed through this operation; use `/monit/rule/move` to move the rule to another folder.\n- The caller must be able to manage the rule's folder (account owner or admin, creator of the folder or one of its ancestors, or member of the team bound to the folder or an ancestor); otherwise the call returns `AccessDenied`.\n- `name` must be unique within the rule's folder; a duplicate returns `InvalidParameter`.\n- When `enabled` is `true`, `ds_type` must be a datasource type that supports alerting and every ID in `ds_ids` must be an enabled datasource with alerting turned on; otherwise the call returns `InvalidParameter`.\n- Callers other than the account owner or admins need read-only access to every datasource listed in `ds_ids` or currently matched by `ds_list`; otherwise the call returns `AccessDenied` (`no permission to reference datasource \"\"`).\n- The call fails with `AccessDenied` when the account already exceeds its alert rule license limit.\n- If the rule is modified by another request while this one is processed, the call returns HTTP 409 (`UndonedOrderExist`, `alert rule was modified; reload and retry`); fetch the rule again and retry.\n- `account_id`, `creator_*`, `updater_*`, `created_at`, and `updated_at` are maintained by the server; client-supplied values are ignored.\n- The request body may not exceed 1 MiB; a larger body returns HTTP 413 (`EntityTooLarge`). Additional unknown fields are ignored (forward compatibility).\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-v2", "metadata": { "sidebarTitle": "Update alert rule (V2)" @@ -1671,6 +1794,7 @@ "enabled": true, "debug_log_enabled": false, "rule_configs": { + "relate_queries": [], "queries": [ { "name": "A", @@ -1731,6 +1855,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1785,12 +1912,12 @@ "post": { "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.", + "description": "Run a synchronous ad-hoc query against a data source and return a `query_result.v1` result as frames, records, or samples.", "tags": [ "Monitors/Diagnostics" ], "x-mint": { - "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.", + "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- The data source is identified by `ds_type` plus `ds_name`, not by ID. It must belong to the account and be enabled. When the data source restricts querying to certain teams, only members of those teams, its managing team, and account owners or admins can query it; others get `AccessDenied`.\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- Prometheus expressions are syntax-checked before the query is dispatched; an invalid expression returns HTTP 400.\n- The request body is limited to 256 KiB and the complete success response to 10 MiB; either limit returns HTTP 413. A result with more than 1,000 rows fails with HTTP 400. Narrow the time range, reduce fields, or aggregate at the source.\n- Query failures use non-2xx HTTP status codes and the standard error envelope.\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 structured data" @@ -1987,7 +2114,7 @@ { "labels": { "__name__": "up", - "instance": "10.101.214.50:7070" + "instance": "203.0.113.10:9090" }, "value": 1 } @@ -2111,7 +2238,7 @@ "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.\n\n## Usage\n\n- Two tool families share this entry: diagnostic tools defined by the executing Edge (e.g. `mysql.overview`, `prometheus.metric_trends`) and query tools named `.query`. The tool prefix must match the datasource type.\n- Query tools require the Edge cluster to support Explore queries (protocol milestone v0.68.0); diagnostic tools require the v0.71.0 base invoke protocol. Unsupported clusters fail with `edge_upgrade_required`, `mixed_edge_versions`, or `edge_version_unknown`; never fall back to `/monit/query/data` or another endpoint automatically.\n- For query tools, `params` follows the per-datasource schema named in the `tool` field description. `expr` and `execution` are always required. `limit`/`direction` only bound raw-log retrieval, never SQL rows or scanned data. Unknown extension fields are tolerated but never executed or forwarded.\n- Query `data` is the complete Explore result: `format` is `explore_result.v1` and `result.kind` is `samples`, `frames`, or `logs`; log results keep `applied_limit` and `has_more`. Query results never synthesize `summary` or `truncated`.\n- Request body limit 128 KiB; complete success response limit 10 MiB for both families; diagnostic tool timeout at most 25 seconds.", + "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.\n\n## Usage\n\n- The caller needs query access to the datasource (see `readonly_team_ids` on the datasource); without it the call fails with 403 `access_denied`. A datasource in another account returns 404 `datasource_not_found`.\n- Diagnostic tools exist only for datasource types `mysql`, `postgres`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`, `elasticsearch`, `prometheus`, `loki` and `victorialogs`; `oracle`, `clickhouse`, `sls` and `tencent_cls` support only their `.query` tool. Other combinations fail with `invalid_request`.\n- Two tool families share this entry: diagnostic tools defined by the executing Edge (e.g. `mysql.overview`, `prometheus.metric_trends`) and query tools named `.query`. The tool prefix must match the datasource type.\n- Query tools require the Edge cluster to support Explore queries (protocol milestone v0.68.0); diagnostic tools require the v0.71.0 base invoke protocol. Unsupported clusters fail with `edge_upgrade_required`, `mixed_edge_versions`, or `edge_version_unknown`; never fall back to `/monit/query/data` or another endpoint automatically.\n- For query tools, `params` follows the per-datasource schema named in the `tool` field description. `expr` and `execution` are always required. `limit`/`direction` only bound raw-log retrieval, never SQL rows or scanned data. Unknown extension fields are tolerated but never executed or forwarded.\n- Query `data` is the complete Explore result: `format` is `explore_result.v1` and `result.kind` is `samples`, `frames`, or `logs`; log results keep `applied_limit` and `has_more`. Query results never synthesize `summary` or `truncated`.\n- Request body limit 128 KiB; complete success response limit 10 MiB for both families; diagnostic tool timeout at most 25 seconds.", "href": "/en/api-reference/monitors/data-sources/monit-datasource-tools-invoke", "metadata": { "sidebarTitle": "Invoke datasource tool" @@ -2208,7 +2335,7 @@ } }, "400": { - "description": "Standard HTTP error; error.reason: invalid_request.", + "description": "Standard HTTP error. `error.reason` is `invalid_request` for malformed or out-of-range parameters, a disabled data source, an unsupported data source type, or a data source without an Edge cluster. A data source ID that does not exist returns code `ResourceNotFound` without a `reason`.", "content": { "application/json": { "schema": { @@ -2221,17 +2348,7 @@ "$ref": "#/components/responses/Unauthorized" }, "403": { - "description": "Standard HTTP error; error.reason: access_denied.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "Standard HTTP error; error.reason: datasource_not_found.", + "description": "The caller is not allowed to query this data source. `error.code` is `AccessDenied`; there is no `error.reason`.", "content": { "application/json": { "schema": { @@ -2241,7 +2358,7 @@ } }, "413": { - "description": "Standard HTTP error; error.reason: source_too_large, result_too_large.", + "description": "Standard HTTP error. `error.reason`: `too_many_rows`, `source_too_large`, or `result_too_large`. A request body above 256 KiB also returns 413, without a `reason`.", "content": { "application/json": { "schema": { @@ -2281,7 +2398,7 @@ } }, "503": { - "description": "Standard HTTP error; error.reason: no_active_edge, edge_upgrade_required, mixed_edge_versions, edge_unavailable.", + "description": "Standard HTTP error. `error.reason`: `no_active_edge`, `edge_version_unknown`, `edge_upgrade_required`, `mixed_edge_versions`, or `edge_unavailable`.", "content": { "application/json": { "schema": { @@ -2306,7 +2423,7 @@ "Monitors/Diagnostics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **16 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |\n| Edge requirement | Supported deployments require **monit-edge v0.68.0 or later** |\n\n## Usage\n\n- Use this endpoint when you need the data source's native result shape; `/monit/query/data` returns the stable `query_result.v1` contract instead. Dispatch on `data.result.kind` (`frames`, `samples`, or `logs`) here.\n- `execution.kind` decides which companion fields are accepted: `instant` needs only `to_ms`, `range` requires `from_ms`, `to_ms`, and `max_data_points`, and `window` takes `from_ms` and `to_ms`. `step_seconds` is not accepted; the step is derived from `max_data_points` and `min_step_seconds`.\n- `args` carries macro substitutions such as Grafana-style variables; every value is a string.\n- A `logs` result is capped at 1,000 entries and reports `applied_limit` plus `has_more`. Time-series and sample results are capped at 1,000 items each and the whole success response at 8 MiB.\n- Query execution may take up to 35 seconds across WebAPI forwarding and Edge execution. Configure client timeouts to at least 40 seconds.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **16 requests/second** per account |\n| Permissions | **Datasources Read** (`monit`) |\n| Edge requirement | Supported deployments require **monit-edge v0.68.0 or later** |\n\n## Usage\n\n- Use this endpoint when you need the data source's native result shape; `/monit/query/data` returns the stable `query_result.v1` contract instead. Dispatch on `data.result.kind` (`frames`, `samples`, or `logs`) here.\n- The data source is identified by `datasource_id`. It must belong to the account, be enabled, have an Edge cluster, and be one of `prometheus`, `elasticsearch`, `loki`, `clickhouse`, `mysql`, `oracle`, `postgres`, `sls`, `victorialogs`, or `tencent_cls`. When the data source restricts querying to certain teams, only members of those teams, its managing team, and account owners or admins can query it.\n- `execution.kind` decides which companion fields are accepted: `instant` needs `to_ms` (`from_ms` is optional), `range` requires `from_ms`, `to_ms`, and `max_data_points`, and `window` requires `from_ms` and `to_ms`. When both times are given, `from_ms` must be less than `to_ms`. `step_seconds` is not accepted; the step is derived from `max_data_points` and `min_step_seconds`.\n- `args` is required (send `{}` when unused) and carries macro substitutions such as Grafana-style variables; every value is a string. Unknown or duplicate JSON keys are rejected.\n- A `logs` result is capped at 1,000 entries (100 for `sls`) and reports `applied_limit` plus `has_more`. A `frames` result holds at most 1,000 frames, 1,000 table rows in total, and 100,000 values in total; a `samples` result holds at most 1,000 samples. The request body is limited to 256 KiB and the whole success response to 10 MiB.\n- Failures use the standard error envelope. `error.reason` is a stable machine-readable value; a data source ID that does not exist returns HTTP 400 with code `ResourceNotFound` and no `reason`.\n- Query execution may take up to 35 seconds across WebAPI forwarding and Edge execution. Configure client timeouts to at least 40 seconds.", "href": "/en/api-reference/monitors/diagnostics/monit-read-query-explore", "metadata": { "sidebarTitle": "Run Explore query" @@ -2331,11 +2448,11 @@ { "name": "X-DSID", "in": "header", - "required": true, + "required": false, "schema": { "type": "string" }, - "description": "Data source ID to query. Must reference a Prometheus-compatible data source owned by the authenticated account." + "description": "Data source ID to query, as a decimal string. Must reference a Prometheus data source owned by the authenticated account. When omitted, the request is served by the platform's own Prometheus instead of one of your data sources." } ], "responses": { @@ -2358,7 +2475,7 @@ } }, "400": { - "description": "The `X-DSID` header is missing or invalid, the data source does not exist, or it is not a Prometheus data source. Returned as `text/plain`.", + "description": "The `X-DSID` header is not a number, the data source is not a Prometheus data source, or no monit-edge is registered for the data source's cluster. Returned as `text/plain`.", "content": { "text/plain": { "schema": { @@ -2370,18 +2487,14 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, - "500": { - "description": "The data source lookup or the proxied request failed. Returned as `text/plain`.", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } + "403": { + "$ref": "#/components/responses/Forbidden" }, - "503": { - "description": "No monit-edge in the data source's cluster supports the data source resource proxy. Returned as `text/plain`; upgrade monit-edge.", + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "description": "The data source does not exist or belongs to another account (message `data source not found`), or the data source lookup or proxied request failed. Returned as `text/plain`.", "content": { "text/plain": { "schema": { @@ -2396,7 +2509,7 @@ "Monitors/Data sources" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n| Edge requirement | Supported deployments require **monit-edge v0.35.0 or later** |\n\n## Usage\n\n- Pass the target data source in the `X-DSID` header. It must be a Prometheus-compatible data source owned by the authenticated account; use `/monit/datasource/list` to obtain its ID.\n- The 200 body is the data source's native Prometheus HTTP API payload, **not** the standard `{ request_id, data }` envelope. Failures raised before the data source is reached are returned as `text/plain` with the matching 4xx or 5xx status.\n- When `X-DSID` is omitted, the request falls back to the platform's own Prometheus proxy. Send the header to query a specific data source.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | Any valid `app_key` (read-only; not gated by a specific permission class) |\n| Edge requirement | Querying a specific data source requires **monit-edge v0.35.0 or later** |\n\n## Usage\n\n- Pass the target data source ID in the `X-DSID` header. It must belong to the authenticated account and be a Prometheus data source; use `/monit/datasource/list` to obtain its ID.\n- The 200 body is the data source's native Prometheus HTTP API payload, **not** the standard `{ request_id, data }` envelope. Query-string parameters are forwarded unchanged, so Prometheus's own parameters such as `match[]`, `start`, and `end` work.\n- When `X-DSID` is omitted, or any monit-edge of the data source's cluster is older than v0.35.0, the request is answered by the platform's own Prometheus instead of your data source. Send the header and keep monit-edge up to date to get your data source's values.\n- Failures raised before the data source is reached are returned as `text/plain` with the matching 4xx or 5xx status. A status of 400 or above returned by the data source itself is passed through with its own body.", "href": "/en/api-reference/monitors/data-sources/monit-prometheus-read-label-values", "metadata": { "sidebarTitle": "List Prometheus label values" @@ -2413,7 +2526,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- The caller supplies `dashboard_id`, so a retried request after a timeout fails with `DashboardIDConflict` instead of creating a second dashboard.\n- `definition` is bounded at 1 MiB and the request body at 2 MiB.\n- Audit-logged.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- The caller generates `dashboard_id` (a lowercase canonical UUIDv7). Retrying after a timeout with the same ID fails with `DashboardIDConflict` (HTTP 409) instead of creating a second dashboard.\n- `folder_id` must be one of the folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder; otherwise the call fails with `FolderNotFound` (HTTP 404).\n- A new dashboard starts at `revision` 1; send it as `expected_revision` on the next update, move or delete.\n- An invalid `definition` returns `InvalidParameter` (HTTP 400) whose message lists each violation as `: `. A definition over 1 MiB or over a count limit such as sections per tab, panels, queries or variables, or a request body over 2 MiB, returns `EntityTooLarge` (HTTP 413); a `schema_version` other than `dashboard.v1` returns `UnsupportedSchemaVersion` (HTTP 422).\n- Audit-logged.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-create", "metadata": { "sidebarTitle": "Create dashboard" @@ -2518,7 +2631,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -2652,7 +2765,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -2691,7 +2804,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | any valid `app_key`; the result is limited to folders its owner can read |\n\n## Usage\n\n- A dashboard in the trash returns `DashboardDeleted` rather than the definition.\n- This read is not permission-gated beyond folder readability: an `app_key` only sees dashboards in folders its owner can read.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Only dashboards in folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder are visible; any other dashboard returns `DashboardNotFound` (HTTP 404).\n- A dashboard in the trash returns `DashboardDeleted` (HTTP 410) instead of its definition; find it with `POST /monit/dashboard/trash/list` and bring it back with `POST /monit/dashboard/restore`.\n- Send the returned `revision` as `expected_revision` on the next update, move or delete.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-get", "metadata": { "sidebarTitle": "Get dashboard detail" @@ -2796,7 +2909,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -2878,7 +2991,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- The whole definition is sent — this is not a partial update.\n- `expected_revision` must equal the stored revision or the call fails with `DashboardRevisionConflict`.\n- A byte-identical definition sets `changed` to false and does not create a revision.\n- The response `resource` is `null` only if the caller lost read access to the folder during the call.\n- Audit-logged.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- Send the whole definition; anything left out is removed, not kept from the stored version.\n- `expected_revision` must equal the stored revision, otherwise the call fails with `DashboardRevisionConflict` (HTTP 409); re-read the dashboard and retry.\n- On success `revision` goes up by 1 and a revision entry carrying `message` is recorded. When the normalized definition and `schema_version` equal the stored ones, `changed` is false, `revision` stays the same and no revision entry is recorded.\n- Titles and descriptions are trimmed and an omitted numeric `unit` is stored as `unitless`, so the returned `definition` can differ slightly from the request.\n- A dashboard in the trash returns `DashboardDeleted` (HTTP 410); a dashboard whose folder the caller cannot access returns `AccessDenied`. Validation and size errors are the same as for `POST /monit/dashboard/create`.\n- Audit-logged.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-update", "metadata": { "sidebarTitle": "Update dashboard" @@ -2985,7 +3098,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3120,7 +3233,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3160,7 +3273,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- Both the source and the destination folder must be writable.\n- The definition is untouched, so `changed` is false only when the dashboard already sits in `folder_id`.\n- Audit-logged.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- The caller must be able to access both the current folder and the destination (folders they created or that belong to one of their teams, plus subfolders; the account owner and admins can access every folder). An inaccessible current folder returns `AccessDenied`; a missing or inaccessible destination returns `FolderNotFound` (HTTP 404).\n- The definition is not touched, but a real move still increments `revision` and records a revision entry. If the dashboard is already in `folder_id`, `changed` is false and nothing is written.\n- `expected_revision` must equal the stored revision, otherwise `DashboardRevisionConflict` (HTTP 409); a dashboard in the trash returns `DashboardDeleted` (HTTP 410).\n- Audit-logged.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-move", "metadata": { "sidebarTitle": "Move dashboard" @@ -3267,7 +3380,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3344,12 +3457,12 @@ "post": { "operationId": "monit-dashboard-write-delete", "summary": "Delete dashboard", - "description": "Move a dashboard to the trash.", + "description": "Move a dashboard to the trash, where it can be restored for 30 days.", "tags": [ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- The delete is soft: the definition is retained for 30 days and can be brought back with `POST /monit/dashboard/restore`.\n- The returned `revision` is the one recorded for the deletion.\n- Audit-logged.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- The delete is soft: the dashboard moves to the trash and is permanently removed, with all its revisions, 30 days after deletion. Restore it before then with `POST /monit/dashboard/restore`.\n- Deleting increments `revision`; the returned `revision` is the value to send as `expected_revision` when restoring.\n- `expected_revision` must equal the stored revision, otherwise `DashboardRevisionConflict` (HTTP 409); deleting a dashboard that is already in the trash returns `DashboardDeleted` (HTTP 410).\n- Audit-logged.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-delete", "metadata": { "sidebarTitle": "Delete dashboard" @@ -3426,7 +3539,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- Omit `folder_id` to restore into the original folder; if that folder is no longer writable the call fails with `RestoreFolderRequired` and you must name a destination.\n- Restoring a dashboard that is not in the trash fails with `DashboardNotFound`.\n- Audit-logged.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- Only dashboards in the trash can be restored; any other dashboard returns `DashboardNotFound` (HTTP 404).\n- `expected_revision` must equal the trashed dashboard's current revision (the `revision` returned by delete and shown in the trash listing), otherwise `DashboardRevisionConflict` (HTTP 409).\n- Omit `folder_id` to restore into the original folder. If that folder no longer exists, the account owner and admins get `RestoreFolderRequired` (HTTP 409) and must pass a destination; other members can only restore dashboards whose original folder they can still access and get `DashboardNotFound` otherwise.\n- A missing or inaccessible destination folder returns `FolderNotFound` (HTTP 404). Restoring increments `revision`.\n- Audit-logged.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-write-restore", "metadata": { "sidebarTitle": "Restore dashboard" @@ -3531,7 +3644,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3607,12 +3720,12 @@ "post": { "operationId": "monit-dashboard-read-list", "summary": "List dashboards", - "description": "List the dashboards in one folder.", + "description": "List the dashboards stored directly in one folder, with word search and paging.", "tags": [ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | any valid `app_key`; the result is limited to folders its owner can read |\n\n## Usage\n\n- `folder_id` is required; the listing always includes descendant folders.\n- `query` is split on whitespace and matched against title and description.\n- Sort keys are limited to `title` and `updated_at` here, at most two, and default to `updated_at` descending.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Only dashboards stored directly in `folder_id` are returned; dashboards in its subfolders are not included. Use `POST /monit/dashboard/search` to look across folders.\n- `folder_id` must be one of the folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder; otherwise the call fails with `FolderNotFound` (HTTP 404). Trashed dashboards are never listed.\n- `query` is split on whitespace; a dashboard matches when every word appears as a substring of its title or description.\n- Sort keys are `title` and `updated_at`, at most two and each used once; the default is `updated_at` descending, and ties are ordered by `dashboard_id`.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-list", "metadata": { "sidebarTitle": "List dashboards" @@ -3717,7 +3830,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | any valid `app_key`; the result is limited to folders its owner can read |\n\n## Usage\n\n- `query` must contain at least one word; an empty query fails with `InvalidParameter`.\n- Scope is limited to the folders the `app_key` owner can read — this endpoint never widens access.\n- Sort keys are limited to `title` and `updated_at`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- `query` must contain at least one word; an empty or whitespace-only query fails with `InvalidParameter`. A dashboard matches when every word appears as a substring of its title or description.\n- Results cover only folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder. Trashed dashboards are never returned.\n- Sort keys are `title` and `updated_at`, at most two and each used once; the default is `updated_at` descending.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-search", "metadata": { "sidebarTitle": "Search dashboards" @@ -3821,7 +3934,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- Sort keys are limited to `title` and `deleted_at` and default to `deleted_at` descending.\n- Unlike the read endpoints this one is gated by Dashboards Manage.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Dashboards Manage** (`monit`) |\n\n## Usage\n\n- Lists trashed dashboards in folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder. Each entry is purged permanently 30 days after deletion.\n- Sort keys are `title` and `deleted_at`, at most two and each used once; the default is `deleted_at` descending.\n- Unlike the other dashboard read endpoints, this one requires the Dashboards Manage permission.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-trash-read-list", "metadata": { "sidebarTitle": "List trashed dashboards" @@ -3921,7 +4034,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | any valid `app_key`; the result is limited to folders its owner can read |\n\n## Usage\n\n- At most 20 revisions are retained, including the current one; older ones are dropped as new revisions land.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Returns at most the 20 most recent revisions, newest first. Create, every update that changes the definition, move, delete and restore each record a revision; older ones are pruned.\n- `message` is present only on revisions written by `POST /monit/dashboard/update` with a message.\n- Only dashboards in folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder are visible, others return `DashboardNotFound` (HTTP 404); a dashboard in the trash returns `DashboardDeleted` (HTTP 410).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-revision-read-list", "metadata": { "sidebarTitle": "List dashboard revisions" @@ -4011,7 +4124,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | any valid `app_key`; the result is limited to folders its owner can read |\n\n## Usage\n\n- Revision numbers are per dashboard and start at 1.\n- A revision that has aged out of the 20-entry window returns `DashboardNotFound`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Revision numbers are per dashboard and start at 1 (the create). Revisions older than the latest 20 are pruned and return `DashboardNotFound` (HTTP 404).\n- Only dashboards in folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder are visible; a dashboard in the trash returns `DashboardDeleted` (HTTP 410), so restore it before reading its history.", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-revision-read-get", "metadata": { "sidebarTitle": "Get dashboard revision" @@ -4112,7 +4225,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -4191,7 +4304,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | any valid `app_key`; the result is limited to folders its owner can read |\n\n## Usage\n\n- Use this to render navigation or let an agent find a panel ID before running it — it avoids paying for the full definition.\n- With `target_id` set, only the branch containing that tab, section or panel is returned; an unknown ID fails with `TargetNotFound`.\n- Panel entries carry only the visualization `kind` and the datasource type, never the panel's queries.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Use it to render navigation or to find a panel ID before calling `POST /monit/dashboard/panel/run`, without downloading queries.\n- With `target_id` set to a tab ID the whole tab is returned; a section ID returns that tab with only that section and no top panels; a panel ID returns only that panel inside its tab or section. An unknown ID fails with `TargetNotFound` (HTTP 404).\n- Panel entries carry only the visualization `kind` and the datasource type, never queries. Datasource variables always report `selection` as `single` without `all`.\n- Only dashboards in folders the `app_key` owner can access: folders they created or that belong to one of their teams, plus all subfolders of those; the account owner and admins can access every folder are visible; a dashboard in the trash returns `DashboardDeleted` (HTTP 410).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-read-outline", "metadata": { "sidebarTitle": "Get dashboard outline" @@ -4334,7 +4447,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** (no per-minute cap) per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- A variable that cannot be resolved does not fail the call: its entry carries an `error` and is left out of `selections`.\n- An explicitly empty `values` selection means unresolved — the resolver will not fall back to the stored default.\n- Selections are bounded at 20 variables; names must match `^[A-Za-z_][A-Za-z0-9_]{0,63}$`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** per account (no per-minute limit) |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Resolves the variables of the current revision of a stored dashboard. `variables` holds the caller's current selections; a variable without an entry falls back to its stored default (`default` for `custom` and `query` variables; for `datasource` variables the `default_datasource_id` if it is still a candidate, otherwise the first candidate ordered by name).\n- A variable that cannot be resolved does not fail the call: its entry carries an `error` and is left out of `selections`. Typical causes are no selection and no default, a selection that is not among the candidates, an unresolved dependency, or an unreachable datasource.\n- An explicitly empty `values` selection means unresolved (`variable_invalid`); the resolver does not fall back to the stored default.\n- Variables are resolved in dependency order, so a variable that depends on a failed variable also reports an error. A name in `variables` that the dashboard does not define fails the call with HTTP 400.\n- Each variable returns at most 1000 candidates, and all candidates together must fit in 8 MiB, otherwise the call fails with `EntityTooLarge` (HTTP 413). `query` variables can only run against Prometheus, MySQL and Loki datasources.\n- The caller must be able to see the dashboard's folder; otherwise the call returns `DashboardNotFound` (HTTP 404). The call has a 35-second overall deadline; exceeding it returns `RuntimeTimeout` (HTTP 504).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-variable-read-resolve", "metadata": { "sidebarTitle": "Resolve dashboard variables" @@ -4455,7 +4568,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** (no per-minute cap) per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- `context` is `new` for a folder that has no dashboard yet, and `existing` for an already stored dashboard; mixing the two fields fails validation.\n- Nothing is persisted, so the response has no `dashboard_id` or `revision`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** per account (no per-minute limit) |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Resolves a draft variable list that is not stored in a dashboard, so an editor can test variables before saving. Nothing is persisted, so the response has no `dashboard_id` or `revision`.\n- `context.kind` is `existing` with `dashboard_id` when the draft belongs to a stored dashboard, or `new` with `folder_id` when the dashboard does not exist yet; sending the other kind's field fails validation (HTTP 400). The caller needs access to that dashboard's folder or to that folder (otherwise 403/404).\n- The draft `variables` are validated like a stored definition (names, dependencies, option limits, at most 20 variables, 1 MiB); a violation fails the call with HTTP 400, or HTTP 413 when a size limit is exceeded.\n- Resolution behaves like variable resolve: a variable that fails carries an `error` and is absent from `selections`, and an empty `values` selection is unresolved.\n- The call has a 35-second overall deadline; exceeding it returns `RuntimeTimeout` (HTTP 504).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-variable-read-preview", "metadata": { "sidebarTitle": "Preview draft variables" @@ -4604,7 +4717,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** (no per-minute cap) per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Use this to show which datasource a panel will hit, and with which expression, before spending a query.\n- `panel_ids` accepts 1–100 unique IDs; a panel missing from the dashboard yields a `state: \"error\"` entry instead of failing the whole call.\n- A panel whose queries only partly resolve reports `state: \"partial\"`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** per account (no per-minute limit) |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Use this to show which datasource a panel will hit, and with which expression, before running it. Nothing is executed.\n- `panel_ids` accepts 1–100 unique IDs, answered in request order. A panel that is not in the dashboard yields `state: \"error\"` with reason `panel_missing` instead of failing the call; a text panel yields `state: \"error\"` with reason `invalid_request`.\n- `state` is `success` when every query of the panel resolved, `partial` when only some did, and `error` when none did. `queries` lists the queries that resolved; `error` reports only the first failure.\n- Built-in time variables (such as the step and the time range) are rendered from `time` and `max_data_points`, unless `preserve_builtin_variables` is `true`, which leaves them verbatim for a caller that renders them with its own window. User variables are always resolved.\n- Panel queries can only be bound to Prometheus, MySQL and Loki datasources. The call has a 35-second overall deadline; exceeding it returns `RuntimeTimeout` (HTTP 504).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-query-read-resolve", "metadata": { "sidebarTitle": "Resolve panel queries" @@ -4730,7 +4843,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** (no per-minute cap) per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Omitting `revision` runs whatever is current; sending it makes the call reject a stale read instead of returning overwritten data.\n- `run_state` aggregates the per-query states — `partial` when some refs succeeded, `incompatible` when the datasource accepted the call but the query does not fit its type.\n- Each ref's `execution` payload is datasource-specific and passed through unmodified; `child_request_id` traces the underlying datasource call.\n- `max_data_points` defaults to 100 and is bounded at 2–5000. The whole response is capped at 8 MiB.\n- Queries inside one panel run with a concurrency of at most 6.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **32 requests/second** per account (no per-minute limit) |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Executes every query of one panel of the current stored dashboard against its datasource. The call returns HTTP 200 even when every query failed; read `run_state` and each ref's `state` and `error`.\n- Omitting `revision` (or sending 0) runs the current revision. Sending it makes the call fail with `DashboardRevisionConflict` (HTTP 409) when the dashboard has changed, instead of returning data for a stale definition.\n- `run_state` summarizes the refs: `success` when all succeeded, `partial` when at least one succeeded and at least one did not, and otherwise `cancelled`, `incompatible` or `error`. A ref is `incompatible` when its query ran but the result does not fit the panel's visualization, for example a configured value field is missing or not numeric.\n- Each ref's `execution` is datasource-specific and passed through unmodified; `child_request_id` identifies the underlying datasource call. Text panels cannot be run (HTTP 400), and an unknown `panel_id` returns `TargetNotFound` (HTTP 404).\n- `max_data_points` defaults to 100 and is bounded at 2–5000. At most 6 queries of one panel run at the same time. A response larger than 8 MiB is rejected with `EntityTooLarge` (HTTP 413) instead of being truncated. The call has a 35-second overall deadline; exceeding it returns `RuntimeTimeout` (HTTP 504).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-panel-read-run", "metadata": { "sidebarTitle": "Run dashboard panel" @@ -4891,7 +5004,7 @@ "Monitors/Dashboards" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **16 requests/second** (no per-minute cap) per account |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Use this to validate a panel while the user is still editing it — nothing is written and no revision is created.\n- The draft is still held to the same limits as a saved dashboard: grid overlap, query counts per visualization kind, and the 1 MiB definition ceiling.\n- The response mirrors a panel run minus `dashboard_id`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **32 requests/second** per account (no per-minute limit) |\n| Permissions | **Datasources Read** (`monit`) |\n\n## Usage\n\n- Use this to check a panel while the user is still editing it: the draft panel and its variables are executed inline, and nothing is written and no revision is created.\n- `context` ties the draft to a stored dashboard (`existing` with `dashboard_id`) or to a folder that has no dashboard yet (`new` with `folder_id`). The caller needs access to that dashboard's folder or to that folder.\n- The draft `panel` and `variables` are validated like a stored definition (grid, query counts per visualization kind, variable references) and must stay within 1 MiB; a violation fails the call with HTTP 400, or HTTP 413 when a size limit is exceeded. Text panels cannot be previewed.\n- The response has the same shape as a panel run, without `dashboard_id` and `revision`. It returns HTTP 200 even when every query failed; read `run_state` and each ref's `state` and `error`.\n- `max_data_points` defaults to 100 and is bounded at 2–5000. At most 6 queries run at the same time. A response larger than 8 MiB is rejected with `EntityTooLarge` (HTTP 413). The call has a 35-second overall deadline; exceeding it returns `RuntimeTimeout` (HTTP 504).", "href": "/en/api-reference/monitors/dashboards/monit-dashboard-panel-read-preview", "metadata": { "sidebarTitle": "Preview draft panel" @@ -5043,7 +5156,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -5116,7 +5229,7 @@ "Monitors/Rule folders" ], "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 Read** or **Node Permissions Read** (`monit`) |\n\n## Usage\n\n- The response is a flat list of every readable folder, not a tree: rebuild the hierarchy from `parent_id` and `parent_path`, and search client-side.\n- Dashboards and alert rules both live in this folder tree, so the same IDs appear as `folder_id` on dashboard payloads.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Alerting Rules Read**, **Alerting Rules Manage**, **Node Permissions Read**, or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- The response is a flat list of the visible folders, not a tree: rebuild the hierarchy from `parent_id` and `parent_path`, and search client-side. An account with no visible folder gets `[]`.\n- Account owners and admins see every folder. Other members see the folders they created, the folders that belong to one of their teams, everything below those folders, and the ancestor folders needed to reach them.\n- Dashboards and alert rules both live in this folder tree, so the same IDs appear as `folder_id` on dashboard payloads and alert rules.", "href": "/en/api-reference/monitors/rule-folders/monit-folder-read-list", "metadata": { "sidebarTitle": "List monitor folders" @@ -5174,6 +5287,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5187,12 +5303,12 @@ "post": { "operationId": "monit-folder-read-health", "summary": "Get monitor folder health", - "description": "Get health summaries for visible folders, including issues in their descendants.", + "description": "Get issue flags for the visible monitor folders, including issues in their descendants.", "tags": [ "Monitors/Rule folders" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **2 requests/second** per account |\n| Permissions | **Alerting Rules Read**, **Alerting Rules Manage**, **Node Permissions Read**, or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Issues include active alerts and alert-rule runtime problems; issues propagate to visible ancestors.\n- This operation scans folder rules and runtime state. Avoid frequent polling.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **2 requests/second** per account |\n| Permissions | **Alerting Rules Read**, **Alerting Rules Manage**, **Node Permissions Read**, or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- `items` has one entry per folder visible to the caller (the same set as `/monit/folder/list`), sorted by `id`.\n- `has_issue` is true when a rule in the folder or in any of its descendants has an active alert or a runtime problem. The issue then also shows on every visible ancestor folder. Only rules in folders the caller can read are counted.\n- This operation scans folder rules and runtime state. Avoid frequent polling.", "href": "/en/api-reference/monitors/rule-folders/monit-folder-read-health", "metadata": { "sidebarTitle": "Get monitor folder health" @@ -5238,6 +5354,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5251,12 +5370,12 @@ "post": { "operationId": "monit-folder-write-create", "summary": "Create monitor folder", - "description": "Create a monitor folder at the root or under an accessible parent folder.", + "description": "Create a monitor folder at the root or under a parent folder the caller may modify.", "tags": [ "Monitors/Rule folders" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Use `parent_id: 0` or omit it to create a root folder. The parent must be accessible.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Use `parent_id: 0` or omit it to create a root folder. To create under a parent, the caller must be allowed to modify it: an account owner or admin, the creator of the parent or of one of its ancestors, or a member of the team assigned to the parent or one of its ancestors. A parent that does not exist returns `InvalidParameter`; a parent you may not modify returns `AccessDenied`.\n- The response is the created folder.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/rule-folders/monit-folder-write-create", "metadata": { "sidebarTitle": "Create monitor folder" @@ -5309,6 +5428,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5338,12 +5460,12 @@ "post": { "operationId": "monit-folder-write-update", "summary": "Update monitor folder", - "description": "Replace the name, note, and team assignment of an accessible monitor folder.", + "description": "Replace the name, note, and team assignment of a monitor folder the caller may modify.", "tags": [ "Monitors/Rule folders" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Send both `id` and `name`. This is a replacement of editable fields: omitting `note` clears it, and omitting `team_id` resets it to 0.\n- Use the move operation to change the parent folder.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Send both `id` and `name`. This is a replacement of editable fields: omitting `note` clears it, and omitting `team_id` resets it to 0.\n- The caller must be allowed to modify the folder: an account owner or admin, the folder's creator or the creator of one of its ancestors, or a member of the team assigned to the folder or one of its ancestors. A missing folder returns `InvalidParameter`; a folder you may not modify returns `AccessDenied`.\n- Use the move operation to change the parent folder. The response is the updated folder.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/rule-folders/monit-folder-write-update", "metadata": { "sidebarTitle": "Update monitor folder" @@ -5396,6 +5518,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5430,7 +5555,7 @@ "Monitors/Rule folders" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- You must have access to both the source and destination folders.\n- `dest_parent_id` is required; send 0 explicitly to move to the root. Moving under the folder itself or a descendant is rejected.\n- Descendant paths are updated in the same transaction.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- The caller must be allowed to modify the source folder and, unless `dest_parent_id` is 0, the destination folder.\n- `dest_parent_id` is required; send 0 explicitly to move to the root. It must differ from `id`, and moving under the folder itself or a descendant is rejected with `InvalidParameter`. Moving a folder to its current parent succeeds without changes.\n- Descendant paths are updated in the same transaction, and the folder and all its descendants record the caller as last updater.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/rule-folders/monit-folder-write-move", "metadata": { "sidebarTitle": "Move monitor folder" @@ -5470,6 +5595,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5497,12 +5625,12 @@ "post": { "operationId": "monit-folder-write-delete", "summary": "Delete monitor folder", - "description": "Delete an accessible monitor folder after removing its children, rules, and dashboards.", + "description": "Delete an empty monitor folder that the caller may modify.", "tags": [ "Monitors/Rule folders" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Only empty folders can be deleted. Child folders, alert rules, and dashboards block deletion with HTTP 409 and error code `FolderNotEmpty`.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Alerting Rules Manage** or **Node Permissions Manage** (`monit`) |\n\n## Usage\n\n- Only empty folders can be deleted; nothing inside is removed for you. Child folders, alert rules, and dashboards block deletion with HTTP 409 and error code `FolderNotEmpty`.\n- The caller must be allowed to modify the folder. A missing folder returns `InvalidParameter`; a folder you may not modify returns `AccessDenied`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/monitors/rule-folders/monit-folder-write-delete", "metadata": { "sidebarTitle": "Delete monitor folder" @@ -5542,6 +5670,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5619,7 +5750,7 @@ "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." + "description": "APP Key created in the Flashduty console under My → APP Key. Send it as the `app_key` query parameter or in the `Fd-App-Key` request header. Its effective access is the intersection of the key's permission scope and the creator's current role permissions. Keep it secret." } }, "responses": { @@ -5666,7 +5797,7 @@ } }, "Forbidden": { - "description": "The app_key is valid but lacks permission for this operation.", + "description": "The app_key is valid, but its permission scope or the creator's role does not allow this operation or object.", "content": { "application/json": { "schema": { @@ -5708,7 +5839,7 @@ } }, "TooManyRequests": { - "description": "Rate limit hit. Either the global API limit, a per-account limit, or a per-integration limit.", + "description": "Rate limit hit (per-account limit or the operation's platform-wide limit). Wait for the number of seconds in `Flashcat-Request-Rate-Limit-Delay`, then retry.", "content": { "application/json": { "schema": { @@ -5726,6 +5857,15 @@ } } } + }, + "headers": { + "Flashcat-Request-Rate-Limit-Delay": { + "description": "Seconds until the current rate-limit window resets. Absent when the request was rejected by the gateway's global protection limit.", + "schema": { + "type": "integer", + "minimum": 0 + } + } } }, "ServerError": { @@ -5998,7 +6138,7 @@ }, "content": { "type": "string", - "description": "JSON string of the full rule snapshot at audit time. Populated on `/monit/rule/audit/detail`, omitted on list responses." + "description": "JSON string of the full rule right after the change. Populated on `/monit/rule/audit/detail`, omitted on list responses. Records written by `/monit/rule/v2/create` and `/monit/rule/v2/update` use the `AlertRuleV2` shape; records written by `/monit/rule/update/fields` and `/monit/rule/move` use the stored rule shape, whose checker configs carry legacy recovery settings instead of `recovery_mode` / `end_mode`." }, "creator_id": { "type": "integer", @@ -6018,7 +6158,7 @@ }, "AlertRuleBasic": { "type": "object", - "description": "Basic alert rule information for list views.", + "description": "Basic alert rule information for list views. In `include_descendants: true` listings only `id`, `folder_id` and `name` are filled; the other fields carry zero values.", "required": [ "id", "account_id", @@ -6049,27 +6189,30 @@ "account_id": { "type": "integer", "format": "uint64", - "description": "Account ID." + "description": "ID of the account that owns the rule; `0` in `include_descendants: true` listings." }, "folder_id": { "type": "integer", "format": "uint64", - "description": "Folder ID." + "description": "ID of the folder that directly contains the rule; in `include_descendants: true` listings it can be a descendant of the requested folder." }, "name": { "type": "string", - "description": "Rule name." + "description": "Rule name, unique within its folder (at most 128 characters)." }, "labels": { - "type": "object", + "type": [ + "object", + "null" + ], "additionalProperties": { "type": "string" }, - "description": "Custom labels." + "description": "Custom labels the rule adds to its alert events; `null` in `include_descendants: true` listings." }, "ds_type": { "type": "string", - "description": "Data source type, e.g. `prometheus`." + "description": "Datasource type the rule queries. Types that support alerting: `prometheus`, `elasticsearch`, `loki`, `clickhouse`, `mysql`, `oracle`, `postgres`, `sls`, `tencent_cls`, `victorialogs`. Only enabled rules are checked against this list, so a disabled rule may carry another value; empty in `include_descendants: true` listings." }, "enabled": { "type": "boolean", @@ -6077,7 +6220,7 @@ }, "debug_log_enabled": { "type": "boolean", - "description": "Whether debug logging is enabled." + "description": "Whether debug logging is on; when `true` the edge writes detailed evaluation logs for this rule." }, "cron_pattern": { "type": "string", @@ -6090,7 +6233,7 @@ }, "delay_seconds": { "type": "integer", - "description": "Evaluation delay in seconds." + "description": "Seconds the evaluation query window is shifted back to allow for data ingestion latency." }, "creator_id": { "type": "integer", @@ -6375,7 +6518,7 @@ "cloud", "self-managed" ], - "description": "Deployment type. `cloud` uses Elastic Cloud; `self-managed` uses a self-hosted cluster." + "description": "Deployment type; required. `cloud` uses Elastic Cloud (`address` is not needed); `self-managed` uses a self-hosted cluster (`address` is required)." }, "timeout_mills": { "type": "integer", @@ -6592,31 +6735,40 @@ "description": "Type-specific datasource configuration. Include only the block matching `type_ident`.", "properties": { "prometheus": { - "$ref": "#/components/schemas/DSPrometheusConfig" + "$ref": "#/components/schemas/DSPrometheusConfig", + "description": "Settings for `type_ident` `prometheus`." }, "loki": { - "$ref": "#/components/schemas/DSLokiConfig" + "$ref": "#/components/schemas/DSLokiConfig", + "description": "Settings for `type_ident` `loki`." }, "mysql": { - "$ref": "#/components/schemas/DSMySQLConfig" + "$ref": "#/components/schemas/DSMySQLConfig", + "description": "Settings for `type_ident` `mysql`." }, "oracle": { - "$ref": "#/components/schemas/DSOracleConfig" + "$ref": "#/components/schemas/DSOracleConfig", + "description": "Settings for `type_ident` `oracle`." }, "postgres": { - "$ref": "#/components/schemas/DSPostgresConfig" + "$ref": "#/components/schemas/DSPostgresConfig", + "description": "Settings for `type_ident` `postgres`." }, "clickhouse": { - "$ref": "#/components/schemas/DSClickHouseConfig" + "$ref": "#/components/schemas/DSClickHouseConfig", + "description": "Settings for `type_ident` `clickhouse`." }, "elasticsearch": { - "$ref": "#/components/schemas/DSElasticSearchConfig" + "$ref": "#/components/schemas/DSElasticSearchConfig", + "description": "Settings for `type_ident` `elasticsearch`." }, "sls": { - "$ref": "#/components/schemas/DSSLSConfig" + "$ref": "#/components/schemas/DSSLSConfig", + "description": "Settings for `type_ident` `sls`." }, "victorialogs": { - "$ref": "#/components/schemas/DSVictoriaLogsConfig" + "$ref": "#/components/schemas/DSVictoriaLogsConfig", + "description": "Settings for `type_ident` `victorialogs`." }, "tencent_cls": { "$ref": "#/components/schemas/DSTencentCLSConfig", @@ -6624,23 +6776,28 @@ }, "kafka": { "$ref": "#/components/schemas/DSKafkaConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "Settings for `type_ident` `kafka` (diagnostic-only)." }, "mongodb_mongod": { "$ref": "#/components/schemas/DSMongoDBConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "Settings for `type_ident` `mongodb_mongod` (diagnostic-only); same fields as `mongodb_mongos`." }, "mongodb_mongos": { "$ref": "#/components/schemas/DSMongoDBConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "Settings for `type_ident` `mongodb_mongos` (diagnostic-only); same fields as `mongodb_mongod`." }, "redis_node": { "$ref": "#/components/schemas/DSRedisNodeConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "Settings for `type_ident` `redis_node` (diagnostic-only)." }, "redis_sentinel": { "$ref": "#/components/schemas/DSRedisSentinelConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "Settings for `type_ident` `redis_sentinel` (diagnostic-only)." } } }, @@ -6708,11 +6865,11 @@ }, "basic_auth_username": { "type": "string", - "description": "Basic auth username." + "description": "Basic Auth username, effective when `basic_auth_enabled` is `true`." }, "basic_auth_password": { "type": "string", - "description": "Basic auth password." + "description": "Basic Auth password, effective when `basic_auth_enabled` is `true`. Returned as stored in create, update and info responses." }, "headers": { "type": "array", @@ -6853,26 +7010,46 @@ "edge_cluster_name", "updated_at", "payload", - "alerting_enabled" + "alerting_enabled", + "manage_team_id", + "readonly_team_ids", + "creator_id" ], "properties": { "id": { "type": "integer", "format": "uint64", - "description": "Unique datasource ID." + "description": "Unique datasource ID. Pass it as `id` to update, delete and info, and as `datasource_id` to tool invocation." }, "account_id": { "type": "integer", "format": "uint64", - "description": "Account ID." + "description": "ID of the account that owns the datasource; always the caller's account." }, "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`。" + "enum": [ + "prometheus", + "loki", + "mysql", + "oracle", + "postgres", + "clickhouse", + "elasticsearch", + "sls", + "tencent_cls", + "victorialogs", + "redis_node", + "redis_sentinel", + "mongodb_mongod", + "mongodb_mongos", + "kafka" + ], + "description": "Datasource type.\n\nAlerting types (can evaluate alert rules):\n- `prometheus`: Prometheus-compatible metrics.\n- `loki`: Grafana Loki logs.\n- `mysql`: MySQL.\n- `oracle`: Oracle Database.\n- `postgres`: PostgreSQL.\n- `clickhouse`: ClickHouse.\n- `elasticsearch`: Elasticsearch.\n- `sls`: Alibaba Cloud Simple Log Service.\n- `tencent_cls`: Tencent Cloud Log Service (CLS).\n- `victorialogs`: VictoriaLogs.\n\nDiagnostic-only types (cannot evaluate alerts, `alerting_enabled` is always `false`):\n- `redis_node`: a single Redis node.\n- `redis_sentinel`: Redis Sentinel.\n- `mongodb_mongod`: a MongoDB mongod instance.\n- `mongodb_mongos`: a MongoDB mongos router.\n- `kafka`: a Kafka cluster.\n\nThe `payload` key that holds the type-specific settings has the same name as the type." }, "name": { "type": "string", - "description": "Datasource display name." + "description": "Datasource name, unique within the account across all types." }, "enabled": { "type": "boolean", @@ -6880,11 +7057,11 @@ }, "note": { "type": "string", - "description": "Optional description." + "description": "Free-text note; an empty string when not set." }, "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.", + "description": "Connection address as stored, after normalization. The format depends on `type_ident`; see the `address` field of the create request for each type. At most 4096 characters.", "maxLength": 4096 }, "payload": { @@ -6910,6 +7087,41 @@ "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" + }, + "manage_team_id": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "description": "ID of the managing team. Its members can edit, delete, enable or disable the datasource and view its full configuration. `null` means no managing team: any caller with the Datasources Manage permission can manage it. The creator, the account owner and Admin members can always manage." + }, + "readonly_team_ids": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint64" + }, + "description": "IDs of the teams allowed to query and reference the datasource, in addition to the managing team, the creator, the account owner and Admin members. `null` or an empty array means every member of the account can query it." + }, + "creator_id": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "description": "ID of the member who created the datasource; `null` when not recorded. The creator can always manage the datasource." + }, + "my_perm": { + "type": "string", + "enum": [ + "manage", + "readonly" + ], + "description": "The caller's access level on this datasource. Only present in list responses.\n- `manage`: can edit, delete, enable or disable the datasource, view its configuration and query it.\n- `readonly`: can query and reference the datasource but not change it or read its configuration." } } }, @@ -6919,20 +7131,41 @@ "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`。" + "description": "Return only datasources of this type; omit or leave empty to return all types. An unrecognized value matches nothing and returns an empty array.\n\nAlerting types (can evaluate alert rules):\n- `prometheus`: Prometheus-compatible metrics.\n- `loki`: Grafana Loki logs.\n- `mysql`: MySQL.\n- `oracle`: Oracle Database.\n- `postgres`: PostgreSQL.\n- `clickhouse`: ClickHouse.\n- `elasticsearch`: Elasticsearch.\n- `sls`: Alibaba Cloud Simple Log Service.\n- `tencent_cls`: Tencent Cloud Log Service (CLS).\n- `victorialogs`: VictoriaLogs.\n\nDiagnostic-only types (cannot evaluate alerts, `alerting_enabled` is always `false`):\n- `redis_node`: a single Redis node.\n- `redis_sentinel`: Redis Sentinel.\n- `mongodb_mongod`: a MongoDB mongod instance.\n- `mongodb_mongos`: a MongoDB mongos router.\n- `kafka`: a Kafka cluster.", + "enum": [ + "prometheus", + "loki", + "mysql", + "oracle", + "postgres", + "clickhouse", + "elasticsearch", + "sls", + "tencent_cls", + "victorialogs", + "redis_node", + "redis_sentinel", + "mongodb_mongod", + "mongodb_mongos", + "kafka" + ] + }, + "name": { + "type": "string", + "description": "Return only the datasource whose name equals this value exactly (names are unique within the account, so at most one item). Omit or leave empty for no name filter." } } }, "DataSourceListResponse": { "type": "array", - "description": "List of datasources. The `payload` column is not read by this endpoint, so `payload` is `null` in every item.", + "description": "Datasources of the account that the caller can query, sorted by name; an empty array when nothing matches. `payload` is `null` in every item because the list does not read it; each item also carries `my_perm`.", "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`.", + "description": "Request body for creating or updating a datasource. `id` is required for update and ignored on create. An update replaces `type_ident`, `name`, `note`, `address`, `payload` and `edge_cluster_name` with the values sent, so resend them all; only `enabled`, `alerting_enabled`, `manage_team_id` and `readonly_team_ids` keep their current value when omitted. `address` is required for all types except Elasticsearch with `deployment=cloud`.", "required": [ "type_ident", "name", @@ -6943,32 +7176,49 @@ "id": { "type": "integer", "format": "uint64", - "description": "Datasource ID. Required for update; omit for create." + "description": "Datasource ID. Required for update (an unknown ID, or one in another account, fails with `ResourceNotFound`); ignored on 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`。" + "enum": [ + "prometheus", + "loki", + "mysql", + "oracle", + "postgres", + "clickhouse", + "elasticsearch", + "sls", + "tencent_cls", + "victorialogs", + "redis_node", + "redis_sentinel", + "mongodb_mongod", + "mongodb_mongos", + "kafka" + ], + "description": "Datasource type.\n\nAlerting types (can evaluate alert rules):\n- `prometheus`: Prometheus-compatible metrics.\n- `loki`: Grafana Loki logs.\n- `mysql`: MySQL.\n- `oracle`: Oracle Database.\n- `postgres`: PostgreSQL.\n- `clickhouse`: ClickHouse.\n- `elasticsearch`: Elasticsearch.\n- `sls`: Alibaba Cloud Simple Log Service.\n- `tencent_cls`: Tencent Cloud Log Service (CLS).\n- `victorialogs`: VictoriaLogs.\n\nDiagnostic-only types (cannot evaluate alerts, `alerting_enabled` is always `false`):\n- `redis_node`: a single Redis node.\n- `redis_sentinel`: Redis Sentinel.\n- `mongodb_mongod`: a MongoDB mongod instance.\n- `mongodb_mongos`: a MongoDB mongos router.\n- `kafka`: a Kafka cluster.\n\nThe `payload` key that holds the type-specific settings has the same name as the type." }, "name": { "type": "string", - "description": "Datasource display name. This is the name referenced as `ds_name` in query APIs." + "description": "Datasource name; required and unique within the account across all types. This is the name referenced as `ds_name` in query APIs. Duplicates fail with `InvalidParameter`." }, "note": { "type": "string", - "description": "Optional description." + "description": "Free-text note. On update, an omitted or empty value clears the stored note." }, "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.", + "description": "Connection address, required for every type except `elasticsearch` with `deployment: cloud`. At most 4096 characters after normalization. Format by type:\n- `prometheus`, `loki`, `victorialogs`: HTTP URL; `http://` is prepended when the value does not start with `http`.\n- `mysql`, `oracle`, `postgres`: `host:port`.\n- `clickhouse`: one or more comma-separated `host:port` endpoints; duplicates are rejected.\n- `elasticsearch` with `self-managed`: one or more comma-separated HTTP(S) URLs (scheme defaults to `http://`) that share identical query parameters; duplicates are rejected. Not needed for `cloud`.\n- `sls`: endpoint without the `http://` or `https://` prefix.\n- `tencent_cls`: exactly `cls.tencentcloudapi.com` or `cls.internal.tencentcloudapi.com` (requires Monitors edge >= v0.66.0).\n- `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`: a single `host:port` (bracket IPv6) with no URI, userinfo or query.\n- `kafka`: 1-32 unique comma-separated `host:port` bootstrap addresses (the payload has no broker list).", "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." + "description": "Type-specific configuration block; must include the key named by `type_ident`. An update replaces the whole payload, so resend every setting you want to keep (including credentials of non-diagnostic types, which the info endpoint returns). Exceptions: for the diagnostic types, omit the password (and the Kafka `tls_key`) to keep the stored value or send an empty string to clear it; for `tencent_cls`, an omitted or empty `secret_key` keeps the stored key. Stored secrets are not carried over when `type_ident` changes." }, "edge_cluster_name": { "type": "string", - "description": "Monitors edge cluster name responsible for evaluating rules using this datasource." + "description": "Name of the Monitors edge cluster that evaluates rules and runs queries for this datasource. It must be an existing edge cluster of the account, otherwise the call fails with `InvalidParameter`. Changing it on update closes open alerts of rules that use this datasource." }, "enabled": { "type": "boolean", @@ -6979,6 +7229,27 @@ "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 + }, + "manage_team_id": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "description": "ID of the managing team (see the response field of the same name). On create, omitted means no managing team. On update, omitted keeps the current value, while `null` or `0` clears it. Required whenever `readonly_team_ids` is non-empty.", + "x-flashduty-preserve-absence": true + }, + "readonly_team_ids": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint64" + }, + "description": "IDs of the teams allowed to query and reference the datasource (see the response field of the same name). On create, omitted means unrestricted. On update, omitted keeps the current value, while `null` or an empty array clears it (everyone can query). Duplicates and `0` are dropped. Requires `manage_team_id`: a non-empty list without a managing team fails with `InvalidParameter`.", + "x-flashduty-preserve-absence": true } } }, @@ -6991,7 +7262,7 @@ }, "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.", + "description": "Human-readable error message in the response language (`locale` / `lang` query parameter or `Accept-Language` header). May name the offending field; do not parse it.", "example": "The specified parameter template_id is not valid." }, "reason": { @@ -7007,7 +7278,7 @@ }, "EmptyResponse": { "type": "object", - "description": "Empty response body. The server returns `data: null` on success.", + "description": "No payload. Depending on the operation, `data` is `{}` or omitted from the envelope; rely only on the HTTP 200 status and the absence of `error`.", "properties": {} }, "EnabledTime": { @@ -7019,21 +7290,21 @@ "items": { "type": "integer" }, - "description": "Days of week, 0 = Sunday." + "description": "Days of week the window applies to, `0` = Sunday through `6` = Saturday; non-empty, no duplicates." }, "stime": { "type": "string", - "description": "Start time, e.g. `09:00`." + "description": "Start time in 24-hour `HH:MM` format, e.g. `09:00`." }, "etime": { "type": "string", - "description": "End time, e.g. `18:00`." + "description": "End time in 24-hour `HH:MM` format, 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. |", + "description": "Error code. Every failed response sets `error.code` to one of these stable strings; branch on it rather than on the HTTP status.\n\n| Code | HTTP | Meaning |\n|---|---|---|\n| `OK` | 200 | Reserved; never returned on a failed request. |\n| `InvalidParameter` | 400 | A parameter is missing, has the wrong type, or failed validation; `message` usually names the field. |\n| `BadRequest` | 400 | The request breaks a business rule or conflicts with the current state of an object; `message` says which. |\n| `InvalidContentType` | 400 | The body is not sent as `application/json`. |\n| `ResourceNotFound` | 400 | The referenced object does not exist in this account or was deleted. Returned as HTTP 400, not 404. |\n| `NoLicense` | 400 | The account's plan does not include the feature, a plan quota is used up, the plan has expired, or credits are insufficient. |\n| `ReferenceExist` | 400 | The object is still referenced by other objects, so it cannot be deleted. |\n| `Unauthorized` | 401 | The APP Key is missing, invalid, or deleted. |\n| `BalanceNotEnough` | 402 | Console-only (billing); not returned by Open API operations. |\n| `AccessDenied` | 403 | The APP Key's permission scope or the creator's role does not allow this operation or object. |\n| `RouteNotFound` | 404 | No operation matches the HTTP method and path. |\n| `MethodNotAllowed` | 405 | The path exists but not for this HTTP method. |\n| `UndonedOrderExist` | 409 | Console-only (billing); not returned by Open API operations. |\n| `EntityTooLarge` | 413 | The request body exceeds the size limit. |\n| `RequestLocked` | 423 | Console-only (sign-in protection); not returned by Open API operations. |\n| `RequestVerifyRequired` | 428 | Console-only (verification code); not returned by Open API operations. |\n| `DangerousOperation` | 428 | Console-only (MFA for high-risk actions); not returned by Open API operations. |\n| `RequestTooFrequently` | 429 | A rate limit was hit; wait for the `Flashcat-Request-Rate-Limit-Delay` response header (seconds) before retrying. |\n| `InternalError` | 500 | Unexpected server error; retry with backoff and include `request_id` when reporting. |\n| `ServiceUnavailable` | 503 | A backend dependency is overloaded or unavailable; retry with backoff. |", "enum": [ "OK", "InvalidParameter", @@ -7048,35 +7319,35 @@ "RouteNotFound", "MethodNotAllowed", "UndonedOrderExist", - "RequestLocked", "EntityTooLarge", - "RequestTooFrequently", + "RequestLocked", "RequestVerifyRequired", "DangerousOperation", + "RequestTooFrequently", "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." + "OK": "Reserved; never returned on a failed request.", + "InvalidParameter": "A parameter is missing, has the wrong type, or failed validation; `message` usually names the field.", + "BadRequest": "The request breaks a business rule or conflicts with the current state of an object; `message` says which.", + "InvalidContentType": "The body is not sent as `application/json`.", + "ResourceNotFound": "The referenced object does not exist in this account or was deleted. Returned as HTTP 400, not 404.", + "NoLicense": "The account's plan does not include the feature, a plan quota is used up, the plan has expired, or credits are insufficient.", + "ReferenceExist": "The object is still referenced by other objects, so it cannot be deleted.", + "Unauthorized": "The APP Key is missing, invalid, or deleted.", + "BalanceNotEnough": "Console-only (billing); not returned by Open API operations.", + "AccessDenied": "The APP Key's permission scope or the creator's role does not allow this operation or object.", + "RouteNotFound": "No operation matches the HTTP method and path.", + "MethodNotAllowed": "The path exists but not for this HTTP method.", + "UndonedOrderExist": "Console-only (billing); not returned by Open API operations.", + "EntityTooLarge": "The request body exceeds the size limit.", + "RequestLocked": "Console-only (sign-in protection); not returned by Open API operations.", + "RequestVerifyRequired": "Console-only (verification code); not returned by Open API operations.", + "DangerousOperation": "Console-only (MFA for high-risk actions); not returned by Open API operations.", + "RequestTooFrequently": "A rate limit was hit; wait for the `Flashcat-Request-Rate-Limit-Delay` response header (seconds) before retrying.", + "InternalError": "Unexpected server error; retry with backoff and include `request_id` when reporting.", + "ServiceUnavailable": "A backend dependency is overloaded or unavailable; retry with backoff." }, "example": "InvalidParameter" }, @@ -7122,11 +7393,11 @@ "properties": { "name": { "type": "string", - "description": "Rule name." + "description": "Name of the rule this result belongs to; `id: ` when the rule ID does not exist." }, "message": { "type": "string", - "description": "Empty on success, error message on failure." + "description": "Outcome for this rule. On success it is empty for `/monit/rule/update/fields` and a localized success text (`Move successfully` / `移动成功`) for `/monit/rule/move`; on failure it carries the error message." } } }, @@ -7424,7 +7695,7 @@ "type": "integer", "format": "uint64" }, - "description": "Rule IDs to update." + "description": "IDs of the rules to update; must contain at least one ID." }, "fields": { "type": "array", @@ -7448,18 +7719,18 @@ "repeat_total" ] }, - "description": "Field names to update. Only listed fields are updated, taking new values from the same-named request fields; values for unlisted fields are silently ignored." + "description": "Names of the fields to update. Each listed field takes the value of the same-named request field, and is set to its zero value when that value is omitted; values sent for unlisted fields are ignored. An unknown name fails the whole call with `InvalidParameter`." }, "labels": { "type": "object", "additionalProperties": { "type": "string" }, - "description": "Custom label key-value pairs; replaces existing labels as a whole. Effective only when `fields` includes `labels`." + "description": "Custom label key-value pairs; replaces existing labels as a whole. Effective only when `fields` includes `labels`; cannot be sent together with `labels_patch`." }, "ds_type": { "type": "string", - "description": "Datasource type identifier. Effective only when `fields` includes `ds_type`." + "description": "Datasource type identifier. Enabled rules must use a type that supports alerting: `prometheus`, `elasticsearch`, `loki`, `clickhouse`, `mysql`, `oracle`, `postgres`, `sls`, `tencent_cls`, `victorialogs`. Effective only when `fields` includes `ds_type`." }, "ds_list": { "type": "array", @@ -7490,7 +7761,7 @@ }, "timezone": { "type": "string", - "description": "Timezone in which the rule executes. IANA timezone name; defaults to `Asia/Shanghai`.", + "description": "Timezone the rule runs in, as an IANA name (e.g. `Asia/Shanghai`, `UTC`); empty falls back to `Asia/Shanghai`. Effective only when `fields` includes `timezone`.", "default": "Asia/Shanghai" }, "delay_seconds": { @@ -7509,11 +7780,11 @@ "additionalProperties": { "type": "string" }, - "description": "Annotation key-value pairs delivered with alert events; keys must not start with `$` (reserved for query fields). Effective only when `fields` includes `annotations`." + "description": "Annotation key-value pairs delivered with alert events; replaces existing annotations as a whole, and keys must not start with `$` (reserved for query fields). Effective only when `fields` includes `annotations`; cannot be sent together with `annotations_patch`." }, "description": { "type": "string", - "description": "Rule description (Markdown). Effective only when `fields` includes `description`." + "description": "Rule description, rendered according to the rule's existing `description_type` (which this endpoint cannot change). Effective only when `fields` includes `description`." }, "channel_ids": { "type": "array", @@ -7526,20 +7797,20 @@ "repeat_interval": { "type": "integer", "format": "int64", - "description": "Interval in seconds between repeated alert notifications. Effective only when `fields` includes `repeat_interval`." + "description": "Interval in seconds between repeated alert notifications; values below 1 fall back to 3600, maximum 2147483647. Effective only when `fields` includes `repeat_interval`." }, "repeat_total": { "type": "integer", "format": "int64", - "description": "Maximum number of repeated notifications. Effective only when `fields` includes `repeat_total`." + "description": "Maximum number of repeated notifications; values below 1 fall back to 3, maximum 2147483647. Effective only when `fields` includes `repeat_total`." }, "labels_patch": { "$ref": "#/components/schemas/StringMapPatch", - "description": "Partial label update. Effective only when `fields` includes `labels`; takes precedence over `labels` when both are sent." + "description": "Partial label update that keeps unmentioned labels. Requires `labels` in `fields` and cannot be sent together with `labels`; otherwise the call returns `InvalidParameter`." }, "annotations_patch": { "$ref": "#/components/schemas/StringMapPatch", - "description": "Partial annotation update. Effective only when `fields` includes `annotations`; takes precedence over `annotations` when both are sent." + "description": "Partial annotation update that keeps unmentioned annotations. Requires `annotations` in `fields` and cannot be sent together with `annotations`; otherwise the call returns `InvalidParameter`." } } }, @@ -7565,7 +7836,7 @@ "id": { "type": "integer", "format": "uint64", - "description": "Audit record ID — the `id` of an audit row returned by `POST /monit/rule/audits`, NOT the rule ID. Passing a rule ID returns HTTP 400." + "description": "Audit record ID — the `id` of a row returned by `POST /monit/rule/audits`, not the rule ID. A rule ID is looked up as an audit record ID, which usually returns `InvalidParameter` (`alert rule audit not found`) or an unrelated record." } } }, @@ -7581,7 +7852,7 @@ "type": "integer", "format": "uint64" }, - "description": "Rule IDs." + "description": "IDs of the alert rules to delete; must contain at least one ID. Get them from `POST /monit/rule/list/basic`." } } }, @@ -7606,15 +7877,15 @@ "folder_id": { "type": "integer", "format": "uint64", - "description": "Folder ID. Must be an existing folder; `0` is rejected with a `folder_not_found` error." + "description": "ID of the folder to list. Must be an existing folder the caller can manage; `0` or an unknown ID returns `InvalidParameter`." }, "include_descendants": { "type": "boolean", - "description": "Also include rules from all descendant folders. When `true`, each returned item carries only `id`, `folder_id` and `name`; combine with `query` / `limit` for rule-picker scenarios." + "description": "Also search all descendant folders. When `true`, results are sorted by name, capped by `limit`, and each item fills only `id`, `folder_id` and `name` (other fields carry zero values); combine with `query` for rule-picker scenarios." }, "query": { "type": "string", - "description": "Rule name fuzzy filter; only effective when `include_descendants` is `true`." + "description": "Filter by rule name substring; a numeric value also matches the rule with that ID. Only effective when `include_descendants` is `true`." }, "limit": { "type": "integer", @@ -7637,12 +7908,12 @@ "type": "integer", "format": "uint64" }, - "description": "Rule IDs to move." + "description": "IDs of the rules to move; must contain at least one ID." }, "dest_folder_id": { "type": "integer", "format": "uint64", - "description": "Destination folder ID. Obtainable via `POST /monit/folder/list`." + "description": "Destination folder ID, from `POST /monit/folder/list`. Must be non-zero; a folder that does not exist or that the caller cannot manage fails the whole call with `AccessDenied`." } } }, @@ -7748,16 +8019,15 @@ "example": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" }, "data": { - "description": "Endpoint-specific payload. See each operation's 200 response schema." + "description": "Operation-specific payload, documented in each operation's 200 response. Operations without a payload return `{}` or omit `data` entirely." } }, "required": [ - "request_id", - "data" + "request_id" ] }, "QueryDataRequest": { - "description": "Request for the stable structured query endpoint. It accepts the same query fields as the retired rows endpoint.", + "description": "Request body of the structured query endpoint.", "allOf": [ { "$ref": "#/components/schemas/QueryRowsRequest" @@ -7999,33 +8269,49 @@ "account_id": { "type": "integer", "format": "int64", - "description": "Optional consistency check. Must equal the authenticated account when supplied; mismatched values are rejected. Business execution always uses the authenticated account." + "description": "Optional consistency check. When supplied it must equal the authenticated account, otherwise the request fails with `AccessDenied`. The query always runs as the authenticated account." }, "ds_type": { "type": "string", - "description": "Data source type; must match a configured data source under the tenant. Examples: `prometheus`, `loki`, `victorialogs`, `sls`, `elasticsearch`, `mysql`, `postgres`, `oracle`, `clickhouse`." + "description": "Data source type. Together with `ds_name` it must match an enabled data source of the account.\n\n- `prometheus`: Prometheus-compatible data source; `expr` is PromQL.\n- `loki`: Grafana Loki; `expr` is LogQL.\n- `victorialogs`: VictoriaLogs.\n- `sls`: Alibaba Cloud Log Service (SLS).\n- `tencent_cls`: Tencent Cloud Log Service (CLS); requires monit-edge v0.66.0 or later.\n- `elasticsearch`: Elasticsearch.\n- `mysql`: MySQL; `expr` is SQL.\n- `postgres`: PostgreSQL; `expr` is SQL.\n- `oracle`: Oracle Database; `expr` is SQL.\n- `clickhouse`: ClickHouse; `expr` is SQL.\n\nOther data source types (for example MongoDB, Redis, or Kafka) are rejected.", + "enum": [ + "clickhouse", + "elasticsearch", + "loki", + "mysql", + "oracle", + "postgres", + "prometheus", + "sls", + "tencent_cls", + "victorialogs" + ] }, "ds_name": { "type": "string", - "description": "Data source name; must match a configured data source under the tenant." + "description": "Data source name, as returned by `/monit/datasource/list`. The data source must be enabled; a name that matches no data source of the account returns HTTP 400." }, "expr": { "type": "string", - "description": "Query expression. Syntax depends on `ds_type` and is interpreted by the corresponding monit-edge client (PromQL for Prometheus, LogQL for Loki, SQL for SQL sources, etc.)." + "description": "Query expression in the language of `ds_type` (PromQL for `prometheus`, LogQL for `loki`, SQL for SQL sources, and so on). Required, at most 64 KiB (12 KiB for `tencent_cls`). Loki's `$__auto` is not supported here; use a fixed duration such as `[5m]`. Prometheus expressions are syntax-checked before dispatch.", + "minLength": 1 }, "delay_seconds": { "type": "integer", - "description": "Look-back offset in seconds applied to point-in-time queries (Prometheus, Loki stats, VictoriaLogs stats). Ignored for raw / detail queries.", - "default": 0 + "description": "Look-back offset in seconds, from 0 to 86400. Applied to point-in-time queries (Prometheus, Loki stats, VictoriaLogs stats); ignored for raw and detail queries. When `args` carries an absolute `.time` and the Edge is v0.74.0 or later, the absolute time takes precedence and this offset is not applied.", + "default": 0, + "minimum": 0, + "maximum": 86400 }, "args": { "type": "object", - "description": "Polymorphic key/value extension parameters forwarded verbatim to monit-edge. All values must be strings, and keys are always namespaced by source (e.g. `sls.project`, `loki.type`). Validation depends on `ds_type`: SLS requires `sls.project` + `sls.logstore`. Elasticsearch accepts `es.type` of `sql`, or omitted — any other value is rejected. Loki and VictoriaLogs accept `.type` of `stats`, `raw`, or omitted; `raw` additionally requires a time range, either `.start` + `.end` or `.timespan.value` + `.timespan.unit` (unit one of `s`, `m`, `h`, `d`). Prometheus and the remaining SQL sources ignore `args` entirely.", + "description": "Extra query parameters as string key/value pairs; keys are namespaced by data source (for example `sls.project`, `loki.type`). At most 128 entries, keys up to 256 bytes, values up to 64 KiB, and 128 KiB in total. What is accepted depends on `ds_type`:\n\n- `prometheus`: optional `prometheus.time`, the evaluation time as Unix seconds, not in the future.\n- `loki`, `victorialogs`: `.type` is `stats` (default) or `raw`. `stats` accepts an optional `.time` (Unix seconds, not in the future). `raw` requires a time range, either `.start` + `.end` (Unix seconds) or `.timespan.value` + `.timespan.unit` (`s`, `m`, `h`, or `d`), spanning at most 6 hours, and accepts `.limit` from 1 to 1001.\n- `sls`: `sls.project` and `sls.logstore` are required. Optional: `sls.lines` (1 to 100), `sls.offset` (0 or more), and a time range of at most 6 hours given as `sls.from` + `sls.to` (Unix seconds) or `sls.timespan.value` + `sls.timespan.unit`.\n- `tencent_cls`: `tencent_cls.region`, `tencent_cls.topic_id`, `tencent_cls.query_mode` (`raw` or `analysis`), and `tencent_cls.syntax` (`cql` or `lucene`) are required. Optional: `tencent_cls.limit` (1 to 100, `raw` mode only, needs monit-edge v0.67.0 or later) and a time range given as `tencent_cls.from` + `tencent_cls.to` (Unix seconds) or `tencent_cls.timespan.value` + `tencent_cls.timespan.unit`, at most 6 hours in `raw` mode and 24 hours in `analysis` mode. Any other key is rejected.\n- `elasticsearch`: `es.type` may be `sql` or omitted; any other value is rejected.\n- `mysql`, `postgres`, `oracle`, `clickhouse`: no arguments are defined.\n\nAn absolute `.time` is only valid for its own data source type. Edges older than v0.74.0 approximate it with a look-back offset and accept only times within the last 86,400 seconds.", "additionalProperties": { "type": "string" } } - } + }, + "description": "Query to run. `ds_type` and `ds_name` together select the data source; `expr` and `args` are interpreted by that data source type." }, "DSTencentCLSConfig": { "type": "object", @@ -8101,7 +8387,7 @@ }, "StringMapPatch": { "type": "object", - "description": "Partial update for a map field: keys in `set` are inserted or replaced, keys in `delete` are removed, all other keys are preserved.", + "description": "Partial update for a map field: keys in `set` are inserted or replaced, keys in `delete` are removed, all other keys are preserved. At least one of `set` / `delete` must be non-empty, keys must not be blank, and a key may not appear in both or twice in `delete`.", "properties": { "set": { "type": "object", @@ -8123,7 +8409,7 @@ "description": "Diagnostic datasource connection configuration.", "properties": { "password": { - "description": "Authentication password; supports ${env:NAME}. Omit on update to preserve; explicitly send an empty string to clear. Literal passwords are omitted from responses.", + "description": "Authentication password; supports ${env:NAME}. Required with `username` for SASL authentication and must be empty when `sasl_mechanism` is `none`. On update, omit to keep the stored password; explicitly send an empty string to clear. Literal passwords are omitted from responses.", "type": "string", "x-flashduty-preserve-absence": true }, @@ -8155,7 +8441,7 @@ }, "tls_enabled": { "default": false, - "description": "Whether TLS is enabled; defaults to false.", + "description": "Whether TLS is enabled; defaults to false. When false, all `tls_*` fields are cleared on save.", "type": "boolean" }, "tls_key": { @@ -8180,7 +8466,7 @@ "type": "boolean" }, "username": { - "description": "Authentication username; an ${env:NAME} reference is supported.", + "description": "Authentication username; an ${env:NAME} reference is supported. Required when `sasl_mechanism` is `plain`, `scram-sha-256` or `scram-sha-512`; must be empty when it is `none`.", "type": "string" } }, @@ -8212,7 +8498,7 @@ }, "tls_enabled": { "default": false, - "description": "Whether TLS is enabled; defaults to false.", + "description": "Whether TLS is enabled; defaults to false. When false, all `tls_*` fields are cleared on save.", "type": "boolean" }, "tls_max_version": { @@ -8232,7 +8518,7 @@ "type": "boolean" }, "username": { - "description": "Authentication username; an ${env:NAME} reference is supported.", + "description": "Authentication username; an ${env:NAME} reference is supported. Must be configured together with `password`.", "type": "string" } }, @@ -8260,7 +8546,7 @@ "type": "integer" }, "username": { - "description": "Authentication username; an ${env:NAME} reference is supported.", + "description": "Authentication username; an ${env:NAME} reference is supported. When set, `password` is required (on update, omit `password` to keep the stored one).", "type": "string" } }, @@ -8282,7 +8568,7 @@ "type": "integer" }, "username": { - "description": "Authentication username; an ${env:NAME} reference is supported.", + "description": "Authentication username; an ${env:NAME} reference is supported. When set, `password` is required (on update, omit `password` to keep the stored one).", "type": "string" } }, @@ -8608,7 +8894,7 @@ "type": "integer" }, "datasource_id": { - "description": "Datasource ID from /monit/datasource/list.", + "description": "ID of the datasource to run the tool against, from `/monit/datasource/list`. The caller needs query access to it. For query tools (`.query`) the ID must not exceed 9007199254740991.", "format": "uint64", "minimum": 1, "type": "integer" @@ -8671,7 +8957,7 @@ "DatasourceToolTruncation": { "properties": { "reason": { - "description": "Why the result was truncated. Presence of this object indicates truncation.", + "description": "Why the result was truncated, as reported by the executing Edge; treat it as an opaque string. The object is present only when the result was truncated.", "type": "string" } }, @@ -8695,12 +8981,12 @@ "format": "int64", "minimum": 1, "maximum": 9007199254740991, - "description": "Data source ID from `/monit/datasource/list`. Must be a positive JavaScript-safe integer and belong to the authenticated account." + "description": "Data source ID from `/monit/datasource/list`. Must be a positive JavaScript-safe integer for an enabled data source of the authenticated account that the caller may query." }, "expr": { "type": "string", "minLength": 1, - "description": "Query expression in the data source's native language (PromQL, LogsQL, SQL, and so on). Non-empty UTF-8 of at most 64 KiB; some data source types enforce a lower limit." + "description": "Query expression in the data source's native language (PromQL, LogsQL, SQL, and so on). Non-empty UTF-8 of at most 64 KiB; `mysql` allows at most 16 KiB and `tencent_cls` at most 12 KiB." }, "args": { "type": "object", @@ -8717,7 +9003,7 @@ }, "QueryExploreExecution": { "type": "object", - "description": "Time semantics of the query. The accepted companion fields depend on `kind`: `instant` takes only `to_ms` (plus optional `from_ms`), `range` requires `from_ms`, `to_ms`, and `max_data_points`, and `window` takes only `from_ms` and `to_ms`. `step_seconds` is never accepted over HTTP.", + "description": "Time semantics of the query. The accepted companion fields depend on `kind`: `instant` takes `to_ms` (and optionally `from_ms`), `range` requires `from_ms`, `to_ms`, and `max_data_points`, and `window` takes only `from_ms` and `to_ms`. When both times are present, `from_ms` must be less than `to_ms`. `step_seconds` is never accepted over HTTP.", "required": [ "kind" ], @@ -8729,17 +9015,19 @@ "range", "window" ], - "description": "Execution kind. `instant` evaluates at a single point in time, `range` evaluates a series over a range, and `window` returns raw rows inside a time window." + "description": "Execution kind.\n\n- `instant`: evaluate at a single point in time.\n- `range`: evaluate a series over `from_ms` to `to_ms`, with a step derived from `max_data_points` and `min_step_seconds`.\n- `window`: query the interval from `from_ms` to `to_ms` with no step." }, "from_ms": { "type": "integer", "format": "int64", - "description": "Unix timestamp in milliseconds for the start of the range. Required for `range` and `window`; optional for `instant`." + "description": "Start of the interval as a Unix timestamp in milliseconds; non-negative and less than `to_ms`. Required for `range` and `window`; optional for `instant`.", + "minimum": 0 }, "to_ms": { "type": "integer", "format": "int64", - "description": "Unix timestamp in milliseconds for the end of the range. Required for every execution kind." + "description": "End of the interval (or the evaluation time for `instant`) as a Unix timestamp in milliseconds; non-negative. Required for every execution kind.", + "minimum": 0 }, "max_data_points": { "type": "integer", @@ -8800,7 +9088,7 @@ "items": { "$ref": "#/components/schemas/ExploreFrame" }, - "description": "Columnar frames. Present when `kind` is `frames`; at most 1,000 frames." + "description": "Columnar frames. Present when `kind` is `frames`; at most 1,000 frames, 1,000 table rows in total, and 100,000 values in total." }, "samples": { "type": "array", @@ -8818,7 +9106,7 @@ }, "applied_limit": { "type": "integer", - "description": "Entry limit applied to a logs result; at most 1000." + "description": "Entry limit applied to a logs result: 1 to 1000 (1 to 100 for `sls` data sources). Present only when `kind` is `logs`." }, "has_more": { "type": "boolean", @@ -8840,7 +9128,7 @@ "table", "time_series" ], - "description": "Frame shape. `table` is an unlabeled table, while `time_series` carries exactly one time field and one float field." + "description": "Frame shape. `table` is an unlabeled table. `time_series` carries exactly one time field and one float field; its time values are strictly increasing and never null." }, "fields": { "type": "array", @@ -8883,6 +9171,17 @@ "values": { "type": "array", "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], "description": "One cell. `time` cells are UTC RFC3339Nano strings; `float` cells may be the strings `NaN`, `+Inf`, and `-Inf`; any cell may be null except a time value inside a `time_series` frame." }, "description": "Column values in row order." @@ -8905,6 +9204,14 @@ "description": "Label set of the sample. May be empty but never null." }, "value": { + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ], "description": "Sample value: a number, or one of the strings `NaN`, `+Inf`, and `-Inf`. Never null." } } @@ -9011,11 +9318,11 @@ "additionalProperties": { "type": "string" }, - "description": "Custom labels." + "description": "Custom labels added to every alert event of the rule. Keys are trimmed, must not be empty and must not start with `__alert_rule_` (reserved); values containing `{{` are rendered as templates when events are delivered; `job` and `instance` values are limited to 255 characters. The serialized object may not exceed 1024 characters." }, "ds_type": { "type": "string", - "description": "Datasource type identifier (e.g. `prometheus`, `elasticsearch`)." + "description": "Datasource type the rule queries. When the rule is enabled it must be a type that supports alerting: `prometheus`, `elasticsearch`, `loki`, `clickhouse`, `mysql`, `oracle`, `postgres`, `sls`, `tencent_cls`, `victorialogs`." }, "ds_list": { "type": "array", @@ -9046,7 +9353,7 @@ }, "cron_pattern": { "type": "string", - "description": "Schedule expression: a 6-field cron (with seconds) or an `@every 30s` interval. Must not start with `CRON_TZ=` or `TZ=`; set the timezone in the `timezone` field instead." + "description": "Schedule expression: a 6-field cron with seconds (e.g. `0 * * * * *`), a descriptor such as `@hourly`, or `@every ` with a whole number of seconds of at least `1s` (e.g. `@every 30s`). Must not start with `CRON_TZ=` or `TZ=`; set the timezone in the `timezone` field instead." }, "timezone": { "type": "string", @@ -9083,15 +9390,15 @@ "items": { "type": "integer" }, - "description": "Days of week (0=Sunday)." + "description": "Days of week the window applies to, `0` = Sunday through `6` = Saturday; non-empty, no duplicates." }, "stime": { "type": "string", - "description": "Start time, e.g. `09:00`." + "description": "Start time in 24-hour `HH:MM` format, e.g. `09:00`." }, "etime": { "type": "string", - "description": "End time, e.g. `18:00`." + "description": "End time in 24-hour `HH:MM` format, e.g. `18:00`." } } } @@ -9114,7 +9421,7 @@ }, "description": { "type": "string", - "description": "Rule description, Markdown format." + "description": "Rule description; rendered as plain text or Markdown according to `description_type`." }, "channel_ids": { "type": "array", @@ -9127,12 +9434,12 @@ "repeat_interval": { "type": "integer", "format": "int64", - "description": "Notification repeat interval in seconds. Values below 1 fall back to the default 3600." + "description": "Notification repeat interval in seconds. Values below 1 fall back to the default 3600; maximum 2147483647." }, "repeat_total": { "type": "integer", "format": "int64", - "description": "Maximum number of repeat notifications. Values below 1 fall back to the default 3." + "description": "Maximum number of repeat notifications. Values below 1 fall back to the default 3; maximum 2147483647." }, "investigation_targets": { "type": "array", @@ -9140,7 +9447,7 @@ "$ref": "#/components/schemas/InvestigationTarget" }, "maxItems": 20, - "description": "Drill-down entries linked from the alert event detail page; at most 20 items, duplicates rejected. On update the field is presence-based: omit it to keep the current value, pass `[]` to clear.", + "description": "Drill-down entries linked from the alert event detail page; at most 20 items, duplicates rejected, and at most 32 KiB once serialized. On update the field is presence-based: omit it to keep the current value, pass `[]` to clear; `null` is rejected.", "x-flashduty-preserve-absence": true }, "creator_id": { @@ -9225,7 +9532,7 @@ }, "relate_queries": { "type": "array", - "description": "Optional auxiliary queries whose results attach to alert events as context. Each entry needs a unique `name` (not colliding with any query name) and a non-empty `expr`.", + "description": "Optional auxiliary queries whose results attach to alert events as context. Each entry needs a unique `name` (not colliding with any query name) and a non-empty `expr`. Always returned, as `[]` when there are none.", "items": { "type": "object", "properties": { @@ -9544,7 +9851,7 @@ }, "DashboardQuery": { "type": "object", - "description": "Query payload shared by dashboards and drill-down entries.", + "description": "Query payload shared by dashboard panels and alert rule drill-down entries. Template syntax differs by context: dashboard panels use dashboard variables (`${name}`), drill-down entries use event labels (`{{ }}`).", "properties": { "mode": { "type": "string", @@ -9553,18 +9860,18 @@ "range", "window" ], - "description": "Evaluation mode: `instant` evaluates at a single timestamp, `range` evaluates a stepped series, `window` returns raw rows inside a time window." + "description": "Evaluation mode: `instant` = evaluate at a single timestamp; `range` = evaluate a stepped series over the time range; `window` = return raw rows inside the time range. Dashboard panels on Prometheus and Loki accept `instant` or `range` (Loki `logs` panels need `range`); MySQL panels need `window`." }, "expr": { "type": "string", - "description": "Query expression in the target data source's language. May reference event labels through `{{ }}` templates." + "description": "Query expression in the datasource's language. In dashboard panels it may reference variables as `${name}`, `${name:raw}` (one value inserted as is) or `${name:regex}` (values joined as a regex alternation), or as `$name` in Prometheus and Loki; write `$${...}` for a literal. Without a formatter, multi-value or `all` variables and values inside `=~`/`!~` are inserted in regex form, so they cannot be used with `=` or `!=`. MySQL queries do not support variables. In drill-down entries the expression may reference event labels through `{{ }}` templates." }, "args": { "type": "object", "additionalProperties": { "type": "string" }, - "description": "Named query arguments; defaults to an empty object. Values are passed through verbatim and must not contain `{{ }}` templates." + "description": "Named query arguments; defaults to an empty object. In dashboard panels values may use `${name}` templates except for Loki and MySQL datasources. In drill-down entries keys and values must not contain `{{ }}` templates." }, "min_step_seconds": { "type": [ @@ -9574,7 +9881,7 @@ "format": "int64", "minimum": 1, "maximum": 9007199254740, - "description": "Minimum step, in seconds. Only accepted when `mode` is `range`, and must be greater than zero; omit or pass null to let the server decide." + "description": "Minimum step, in seconds; must be greater than zero. In drill-down entries it is only accepted when `mode` is `range`. Omit or pass null to let the server decide." } }, "required": [ @@ -9585,7 +9892,7 @@ }, "DashboardDefinition": { "type": "object", - "description": "Complete dashboard payload stored as a portable `dashboard.v1` document. Unknown keys, duplicate keys, NaN/Inf, over-range numbers and trailing values are rejected; the serialized form must stay within 1 MiB.", + "description": "Complete dashboard payload stored as a portable `dashboard.v1` document. Unknown keys, duplicate keys, trailing values and nesting deeper than 32 levels are rejected, and the serialized form must stay within 1 MiB. Limits: 10 tabs, 10 sections per tab, 30 panels and 100 queries per tab, 100 panels and 300 queries per dashboard, 20 variables.", "properties": { "title": { "type": "string", @@ -9617,7 +9924,7 @@ "$ref": "#/components/schemas/DashboardVariable" }, "maxItems": 20, - "description": "Dashboard variables, at most 20. Names must be unique within the definition and match the variable-name pattern." + "description": "Dashboard variables, at most 20, with unique names. Variables may reference other variables but not in a cycle." }, "tabs": { "type": "array", @@ -9626,7 +9933,7 @@ }, "minItems": 1, "maxItems": 10, - "description": "Tabs, 1–10. Every tab title is unique and every tab or section ID must be a canonical UUIDv7 used only once across the definition." + "description": "Tabs, 1–10. Every tab, section and panel `id` must be a canonical UUIDv7 used only once across the definition. Tab titles do not need to be unique." } }, "required": [ @@ -9681,7 +9988,7 @@ "type": "string", "minLength": 1, "maxLength": 189, - "description": "Tab title, 1–189 Unicode code points. Unique among tabs." + "description": "Tab title, 1–189 Unicode code points after trimming." }, "description": { "type": "string", @@ -9694,7 +10001,7 @@ "$ref": "#/components/schemas/DashboardPanel" }, "maxItems": 30, - "description": "Panels placed directly on the tab, at most 30." + "description": "Panels placed directly on the tab. A tab holds at most 30 panels in total, counting top panels and section panels, and at most 100 queries." }, "sections": { "type": "array", @@ -9742,7 +10049,7 @@ "$ref": "#/components/schemas/DashboardPanel" }, "maxItems": 30, - "description": "Panels in the section, at most 30." + "description": "Panels in the section; they count toward the tab's 30-panel limit." } }, "required": [ @@ -9754,7 +10061,7 @@ }, "DashboardPanel": { "type": "object", - "description": "A single visualization. Panels must not overlap inside the same container; the 24-column grid is validated on save.", + "description": "A single visualization. `datasource_ref` is required for every kind except `text`, where it is forbidden. Panels must not overlap inside the same container; the 24-column grid is validated on save.", "properties": { "id": { "type": "string", @@ -9849,17 +10156,18 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "Datasource ID. Required when `kind` is `fixed`, forbidden when `kind` is `variable`." + "description": "Datasource ID. Required when `kind` is `fixed`, forbidden when `kind` is `variable`.", + "maximum": 9007199254740991 }, "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "Datasource variable name. Required when `kind` is `variable`, forbidden when `kind` is `fixed`." + "description": "Name of a `datasource` variable in the same definition. Required when `kind` is `variable`, forbidden when `kind` is `fixed`." }, "datasource_type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", - "description": "Datasource type identifier, e.g. `prometheus` or `victorialogs`." + "description": "Datasource type identifier: lowercase letters, digits and underscores, starting with a letter. The set is open, so saving accepts any such value, but the dashboard runtime only runs `prometheus`, `mysql` and `loki` datasources; panels on other types fail when run. With `kind` = `variable` it must equal the referenced datasource variable's `datasource_type`." } }, "required": [ @@ -9882,7 +10190,7 @@ "legend_alias": { "type": "string", "maxLength": 1024, - "description": "Optional legend label; supports the same variable templates as `expr`." + "description": "Optional legend label, at most 1024 Unicode code points. The console replaces `{{label}}` with that series label's value (for example `{{env}} requests`); dashboard variables are not substituted here." } }, "required": [ @@ -9926,7 +10234,7 @@ "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "Variable name used in `{{ }}` templates, at most 64 characters. Names starting with `__` are reserved for built-in time variables." + "description": "Variable name, unique within the definition. Queries reference it as `${name}` (or `$name` inside Prometheus and Loki expressions). Names starting with `__` are reserved for the built-in variables `__interval`, `__rate_interval`, `__range` and `__auto`." }, "label": { "type": "string", @@ -9936,7 +10244,7 @@ "datasource_type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", - "description": "Datasource type the candidates are drawn from." + "description": "Type of datasource offered as candidates; candidates are the account's enabled datasources of this type. The set is open, so saving accepts any such value, but the dashboard runtime only runs `prometheus`, `mysql` and `loki` datasources; panels on other types fail when run. " }, "name_patterns": { "type": "array", @@ -9951,7 +10259,8 @@ "default_datasource_id": { "type": "integer", "format": "uint64", - "description": "Default datasource ID. Without a usable default the runtime picks the first candidate by name, then ID." + "description": "Default datasource ID. Without a usable default the runtime picks the first candidate by name, then ID.", + "maximum": 9007199254740991 } }, "required": [ @@ -9974,7 +10283,7 @@ "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "Variable name used in `{{ }}` templates, at most 64 characters. Names starting with `__` are reserved for built-in time variables." + "description": "Variable name, unique within the definition. Queries reference it as `${name}` (or `$name` inside Prometheus and Loki expressions). Names starting with `__` are reserved for the built-in variables `__interval`, `__rate_interval`, `__range` and `__auto`." }, "label": { "type": "string", @@ -10018,7 +10327,7 @@ "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "Variable name used in `{{ }}` templates, at most 64 characters. Names starting with `__` are reserved for built-in time variables." + "description": "Variable name, unique within the definition. Queries reference it as `${name}` (or `$name` inside Prometheus and Loki expressions). Names starting with `__` are reserved for the built-in variables `__interval`, `__rate_interval`, `__range` and `__auto`." }, "label": { "type": "string", @@ -10079,7 +10388,7 @@ }, "DashboardSelection": { "type": "object", - "description": "A concrete selection of variable values. An empty `values` array is valid wire input and means unresolved — the server never substitutes a default for it.", + "description": "A concrete selection of variable values. As a saved variable `default`, `values` must be non-empty and hold exactly one value in `single` mode. In runtime requests an empty `values` array is valid and means unresolved — the server never substitutes a default for it.", "properties": { "kind": { "type": "string", @@ -10166,7 +10475,7 @@ }, "metric": { "type": "string", - "description": "Optional metric used to restrict the series considered." + "description": "Optional metric selector that restricts the series considered; may reference other variables as `${name}` or `$name`." }, "label_filters": { "type": "array", @@ -10188,7 +10497,7 @@ "label": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_:.\\-]{0,189}$", - "description": "Label name." + "description": "Prometheus label name to match, e.g. `job`; letters, digits, `_`, `:`, `.` and `-`, starting with a letter or `_`." }, "op": { "type": "string", @@ -10203,7 +10512,7 @@ "value": { "type": "string", "minLength": 1, - "description": "Matcher value; may reference other variables through `{{ }}`." + "description": "Matcher value; may reference other variables as `${name}`. A multi-value or `all` variable needs `=~` or `!~`." } }, "required": [ @@ -10225,7 +10534,7 @@ }, "expr": { "type": "string", - "description": "SQL statement; may reference other variables through `{{ }}`." + "description": "SQL statement whose result supplies the candidates. SQL variable queries run only on MySQL datasources, and MySQL queries do not support variable references." }, "args": { "type": "object", @@ -10264,7 +10573,7 @@ }, "expr": { "type": "string", - "description": "Logs query expression; may reference other variables through `{{ }}`. May be empty for a Loki datasource, which then lists the field's values across all streams." + "description": "Logs query expression; may reference other variables as `${name}`. Logs variable queries run only on Loki datasources, where `expr` may be empty to list the field's values across all streams." }, "args": { "type": "object", @@ -10287,7 +10596,7 @@ ] }, "DashboardVizConfig": { - "description": "Visualization configuration. `kind` selects the arm and therefore which sibling config object is required; `time_series` also carries the shared numeric options.", + "description": "Visualization configuration. `kind` selects the arm and therefore which sibling fields are allowed; `time_series`, `stat`, `bar` and `gauge` also carry the shared numeric fields `unit`, `decimals` and `threshold`. Fields of another kind are rejected.", "oneOf": [ { "$ref": "#/components/schemas/DashboardTimeSeriesViz" @@ -10354,7 +10663,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second." + "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second. Defaults to `unitless` when omitted." }, "decimals": { "type": [ @@ -10362,7 +10671,8 @@ "null" ], "minimum": 0, - "description": "Fixed decimal places; omit or send null to let the renderer decide." + "description": "Fixed number of decimal places, 0–15; omit or send null to let the console decide.", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10394,15 +10704,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardColumnOption" }, - "description": "Per-column display overrides keyed by field name, at most 100 entries." + "description": "Per-column display overrides keyed by result field name, at most 100 entries. Keys must be non-empty, at most 1024 Unicode code points and not `frame_index` or `field_index`." }, "sort": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardFieldSort" }, - "maxItems": 2, - "description": "Initial sort keys; fields must be unique." + "description": "Initial sort keys, applied in order; each field may appear once." }, "link_columns": { "type": "array", @@ -10448,7 +10757,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second." + "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second. Defaults to `unitless` when omitted." }, "decimals": { "type": [ @@ -10456,7 +10765,8 @@ "null" ], "minimum": 0, - "description": "Fixed decimal places; omit or send null to let the renderer decide." + "description": "Fixed number of decimal places, 0–15; omit or send null to let the console decide.", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10466,7 +10776,9 @@ "items": { "type": "string" }, - "description": "Fields reduced to the displayed values." + "description": "Result fields reduced to the displayed values; at least one, each listed once. Names are matched exactly and must not be `frame_index` or `field_index`.", + "minItems": 1, + "uniqueItems": true }, "reducer": { "type": "string", @@ -10517,7 +10829,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second." + "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second. Defaults to `unitless` when omitted." }, "decimals": { "type": [ @@ -10525,21 +10837,25 @@ "null" ], "minimum": 0, - "description": "Fixed decimal places; omit or send null to let the renderer decide." + "description": "Fixed number of decimal places, 0–15; omit or send null to let the console decide.", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" }, "category_field": { "type": "string", - "description": "Field supplying the category axis." + "description": "Result field supplying the category axis; required, at most 1024 Unicode code points, not `frame_index` or `field_index`.", + "minLength": 1 }, "value_fields": { "type": "array", "items": { "type": "string" }, - "description": "Fields supplying the bar values." + "description": "Result fields supplying the bar values; at least one, each listed once. Names must not be `frame_index` or `field_index`.", + "minItems": 1, + "uniqueItems": true }, "data_link": { "$ref": "#/components/schemas/DashboardDataLink" @@ -10582,7 +10898,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second." + "description": "Display unit for the panel's numeric values: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second. Defaults to `unitless` when omitted." }, "decimals": { "type": [ @@ -10590,7 +10906,8 @@ "null" ], "minimum": 0, - "description": "Fixed decimal places; omit or send null to let the renderer decide." + "description": "Fixed number of decimal places, 0–15; omit or send null to let the console decide.", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10600,7 +10917,9 @@ "items": { "type": "string" }, - "description": "Fields reduced to the gauge value." + "description": "Result fields reduced to the gauge value; at least one, each listed once. Names are matched exactly and must not be `frame_index` or `field_index`.", + "minItems": 1, + "uniqueItems": true }, "reducer": { "type": "string", @@ -10683,7 +11002,7 @@ "markdown": { "type": "string", "maxLength": 65536, - "description": "Markdown body, at most 64 KiB. Only a restricted node set (headings, lists, tables, links, code) survives validation." + "description": "Markdown body, at most 64 KiB. Allowed: paragraphs, headings, lists, block quotes, code blocks and spans, emphasis, tables, horizontal rules and links. Links must be `https://` URLs or site-relative paths starting with `/`. Images, raw HTML and `${` templates are rejected with `InvalidParameter`, not stripped." } }, "required": [ @@ -10761,7 +11080,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "Unit override for the column: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second." + "description": "Unit override for the column: `unitless` = raw number; `ratio` = fraction of 1; `percent` = percentage; `milliseconds` = duration in milliseconds; `seconds` = duration in seconds; `bytes` = size in bytes; `bits` = size in bits; `count_per_second` = per-second count; `bytes_per_second` = bytes per second; `bits_per_second` = bits per second. Defaults to `unitless` when omitted." }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10786,7 +11105,7 @@ "field": { "type": "string", "minLength": 1, - "description": "Field name to sort by." + "description": "Result field name to sort by; at most 1024 Unicode code points, not `frame_index` or `field_index`." }, "direction": { "type": "string", @@ -10804,12 +11123,12 @@ }, "DashboardDataLink": { "type": "object", - "description": "Drill-down link from a table column or bar panel into another dashboard. The target dashboard must exist and the mapping sources must match the source panel's shape.", + "description": "Drill-down link from a table or bar panel into another dashboard. Only the ID format is checked on save; a link to a dashboard that does not exist is accepted. The mapping sources allowed depend on the source panel kind.", "properties": { "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Target dashboard ID." + "description": "ID of the dashboard to open; must be a canonical UUIDv7." }, "target_id": { "type": "string", @@ -10825,7 +11144,7 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardLinkMapping" }, - "description": "Maps target variable names to a source value such as a column or a source variable." + "description": "Values to set in the target dashboard, keyed by target variable name (must match `^[A-Za-z_][A-Za-z0-9_]{0,63}$`); each entry says where the value comes from. Send `{}` for none." } }, "required": [ @@ -10847,15 +11166,15 @@ "series", "value" ], - "description": "Where the value comes from: `variable` = a dashboard variable; `row_column` = a table column (requires `column`); `category` = the bar category; `series` = the series name; `value` = the value itself. `category`, `series` and `value` are only valid for bar panels." + "description": "Where the value comes from: `variable` = the current value of a variable of the source dashboard (requires `name`), allowed on table and bar panels; `row_column` = the clicked row's value in a table column (requires `column`), table panels only; `category` = the clicked bar's category, `series` = its series name, `value` = its value — these three are bar panels only and take no extra fields." }, "column": { "type": "string", - "description": "Source column name; required when `source` is `row_column`." + "description": "Table column (result field) to read; required when `source` is `row_column` and forbidden otherwise." }, "name": { "type": "string", - "description": "Source dashboard variable name; required when `source` is `variable`." + "description": "Variable of the source dashboard to read; required when `source` is `variable` and must exist in the same definition; forbidden for other sources." } }, "required": [ @@ -10869,11 +11188,11 @@ "id": { "type": "integer", "format": "uint64", - "description": "Member ID." + "description": "Member ID of the person who performed the action." }, "name": { "type": "string", - "description": "Member display name." + "description": "Member display name, recorded at the time of the action." } }, "required": [ @@ -10956,13 +11275,13 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "Dashboard ID; pass it to `POST /monit/dashboard/get` for the full definition." }, "folder_id": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "Folder ID." + "description": "ID of the folder the dashboard is stored in." }, "folder_breadcrumb": { "type": "array", @@ -10977,7 +11296,7 @@ }, "description": { "type": "string", - "description": "Dashboard description; empty when unset." + "description": "Dashboard description; omitted when unset." }, "revision": { "type": "integer", @@ -11033,7 +11352,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the trashed dashboard; pass it to `POST /monit/dashboard/restore`." }, "folder_id": { "type": "integer", @@ -11054,13 +11373,13 @@ }, "description": { "type": "string", - "description": "Dashboard description; empty when unset." + "description": "Dashboard description; omitted when unset." }, "revision": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "Revision the dashboard had when deleted." + "description": "Current revision of the trashed dashboard (the deletion bumped it); send it as `expected_revision` to restore." }, "deleted_by": { "$ref": "#/components/schemas/DashboardActor" @@ -11095,7 +11414,7 @@ "total": { "type": "integer", "format": "int64", - "description": "Total number of deleted dashboards." + "description": "Total number of trashed dashboards visible to the caller, across all pages." } }, "required": [ @@ -11105,11 +11424,11 @@ }, "DashboardUpdateOutput": { "type": "object", - "description": "Result of an update or move. `changed` is false when the write was a no-op — the canonical serialized definition matched the stored one byte for byte, in which case `resource` still describes the unchanged dashboard.", + "description": "Result of an update or move. `changed` is false when nothing was written — for update, the normalized definition and `schema_version` equal the stored ones; for move, the dashboard is already in the target folder. `revision` then stays the same and `resource` describes the unchanged dashboard.", "properties": { "changed": { "type": "boolean", - "description": "Whether the stored dashboard actually changed." + "description": "Whether the dashboard was written and its `revision` incremented." }, "resource": { "$ref": "#/components/schemas/DashboardResource" @@ -11127,13 +11446,13 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the dashboard moved to the trash." }, "revision": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "Revision recorded for the deletion." + "description": "Revision after the deletion; send it as `expected_revision` to restore." } }, "required": [ @@ -11148,7 +11467,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the dashboard this revision belongs to." }, "revision": { "type": "integer", @@ -11165,7 +11484,7 @@ "message": { "type": "string", "maxLength": 1024, - "description": "Optional commit message; at most 1024 Unicode code points." + "description": "Message passed to `POST /monit/dashboard/update`; omitted when none was given and on revisions written by create, move, delete and restore." }, "actor": { "$ref": "#/components/schemas/DashboardActor" @@ -11207,7 +11526,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the dashboard this revision belongs to." }, "schema_version": { "type": "string", @@ -11234,7 +11553,7 @@ "message": { "type": "string", "maxLength": 1024, - "description": "Optional commit message." + "description": "Message passed to `POST /monit/dashboard/update`; omitted when none was given." }, "actor": { "$ref": "#/components/schemas/DashboardActor" @@ -11294,7 +11613,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "Dashboard ID, as passed in the request." }, "title": { "type": "string", @@ -11302,7 +11621,7 @@ }, "description": { "type": "string", - "description": "Dashboard description; empty when unset." + "description": "Dashboard description; omitted when unset." }, "revision": { "type": "integer", @@ -11331,7 +11650,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "Folder ID." + "description": "ID of the folder the dashboard is stored in." }, "breadcrumb": { "type": "array", @@ -11357,7 +11676,7 @@ }, "label": { "type": "string", - "description": "Display label; empty when unset." + "description": "Display label; omitted when unset." }, "kind": { "type": "string", @@ -11384,15 +11703,15 @@ "id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Tab ID." + "description": "Tab ID; pass it as `target_id` to narrow the outline to this tab." }, "title": { "type": "string", - "description": "Tab title." + "description": "Tab title as stored in the definition." }, "description": { "type": "string", - "description": "Tab description; empty when unset." + "description": "Tab description; omitted when unset." }, "breadcrumb": { "type": "array", @@ -11431,7 +11750,7 @@ "id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Section ID." + "description": "Section ID; pass it as `target_id` to narrow the outline to this section." }, "title": { "type": "string", @@ -11439,7 +11758,7 @@ }, "description": { "type": "string", - "description": "Section description; empty when unset." + "description": "Section description; omitted when unset." }, "breadcrumb": { "type": "array", @@ -11470,7 +11789,7 @@ "id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Panel ID." + "description": "Panel ID; use it as `panel_id` for `POST /monit/dashboard/panel/run` or as `target_id` here." }, "title": { "type": "string", @@ -11478,7 +11797,7 @@ }, "description": { "type": "string", - "description": "Panel description; empty when unset." + "description": "Panel description; omitted when unset." }, "breadcrumb": { "type": "array", @@ -11492,7 +11811,7 @@ }, "datasource_type": { "type": "string", - "description": "Datasource type the panel queries; empty when the panel has no datasource (text panels)." + "description": "Datasource type from the panel's `datasource_ref`, such as `prometheus`, `mysql` or `loki`; omitted for text panels, which have no datasource. The set is open: it echoes whatever type was saved." } }, "required": [ @@ -11558,7 +11877,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Canonical UUIDv7 of the dashboard." + "description": "Lowercase canonical UUIDv7 generated by the caller; it becomes the dashboard's permanent ID." }, "schema_version": { "type": "string", @@ -11571,7 +11890,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "Folder the dashboard is created in. Must be a folder the caller can write." + "description": "Folder to create the dashboard in; must exist and be accessible to the `app_key` owner, otherwise `FolderNotFound`." }, "definition": { "$ref": "#/components/schemas/DashboardDefinition" @@ -11674,7 +11993,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "Destination folder ID." + "description": "Destination folder ID; must exist and be accessible to the caller, otherwise `FolderNotFound`." } }, "required": [ @@ -11685,7 +12004,7 @@ }, "DashboardDeleteRequest": { "type": "object", - "description": "Move a dashboard to the trash. The definition is retained for 30 days so the delete can be undone with the restore endpoint.", + "description": "Move a dashboard to the trash. It is purged permanently 30 days after deletion; until then the restore endpoint can undo the delete.", "properties": { "dashboard_id": { "type": "string", @@ -11717,7 +12036,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "Revision the caller last read. The write fails with `DashboardRevisionConflict` unless it still matches the stored revision." + "description": "Current revision of the trashed dashboard, as returned by the delete call or listed in the trash. The restore fails with `DashboardRevisionConflict` if it does not match." }, "folder_id": { "type": [ @@ -11726,7 +12045,7 @@ ], "format": "uint64", "minimum": 1, - "description": "Destination folder. Omit to restore to the original folder; when the original folder is no longer writable the call fails with `RestoreFolderRequired` and you must pass one." + "description": "Destination folder. Omit or send null to restore into the original folder; if that folder no longer exists the call fails with `RestoreFolderRequired` and a destination must be passed." } }, "required": [ @@ -11763,12 +12082,12 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "Folder whose dashboards are listed." + "description": "Folder whose directly contained dashboards are listed; subfolders are not included." }, "query": { "type": "string", "maxLength": 128, - "description": "Optional space-separated search words matched against title and description; at most 128 Unicode code points." + "description": "Optional search words separated by whitespace, at most 128 Unicode code points. A dashboard matches when every word appears in its title or description." }, "sort": { "type": "array", @@ -11802,7 +12121,7 @@ "type": "string", "minLength": 1, "maxLength": 128, - "description": "Space-separated search words; at least one word and at most 128 Unicode code points." + "description": "Search words separated by whitespace; at least one word and at most 128 Unicode code points. A dashboard matches when every word appears in its title or description." }, "sort": { "type": "array", @@ -11861,13 +12180,15 @@ "type": "integer", "format": "int64", "minimum": 0, - "description": "Unix timestamp in milliseconds." + "description": "Start of the window as a Unix timestamp in milliseconds. Must be 0 or greater and less than `to_ms`.", + "maximum": 9007199254740991 }, "to_ms": { "type": "integer", "format": "int64", "minimum": 1, - "description": "Unix timestamp in milliseconds." + "description": "End of the window as a Unix timestamp in milliseconds. Must be greater than `from_ms`; `instant` queries are evaluated at this time.", + "maximum": 9007199254740991 } }, "required": [ @@ -11877,15 +12198,15 @@ }, "DashboardRuntimeError": { "type": "object", - "description": "Per-variable or per-query failure. A failed arm does not fail the whole call.", + "description": "Failure of one variable or one query. A failed variable or query does not fail the whole call.", "properties": { "reason": { "type": "string", - "description": "Machine-readable failure reason. Observed values include `invalid_request`, `variable_invalid`, `panel_missing`, `field_missing`, `datasource_permission_denied`, `timeout`, `panel_deadline`, `panel_canceled`, `canceled`, `overloaded`, `source_too_large`, `edge_unavailable`, `edge_upgrade_required`, `edge_version_unknown`, `mixed_edge_versions` and `internal`." + "description": "Machine-readable failure reason. The set is open; current values:\n- `invalid_request`: the query or datasource setup is rejected (unsupported datasource type or query mode, non-empty `args` where none are allowed, a malformed argument).\n- `variable_invalid`: a variable could not be used (no selection and no default, a selection outside the candidates, an unresolved dependency, a bad substitution, or an unusable candidate list).\n- `panel_missing`: the panel is not in the dashboard (queries resolve only).\n- `datasource_permission_denied`: the datasource is missing, disabled, not accessible to the caller, or no accessible datasource matches the variable.\n- `field_missing`, `value_not_scalar`, `empty_field_name`, `duplicate_field_name`, `field_type_changed`: the result does not fit the panel's visualization, or a SQL variable query returned unusable columns.\n- `timeout`: the datasource call timed out; `panel_deadline`: the run hit the overall 35-second deadline.\n- `canceled`, `panel_canceled`: the call was cancelled.\n- `overloaded`: the datasource side is rate limiting.\n- `too_many_rows`, `result_too_large`, `source_too_large`: a row, size or candidate-count limit was exceeded.\n- `edge_unavailable`, `no_active_edge`, `edge_upgrade_required`, `edge_version_unknown`, `mixed_edge_versions`: the Edge cluster of the datasource is not connected, too old, of unknown version, or mixed.\n- `internal`: an unexpected server-side error." }, "message": { "type": "string", - "description": "Human-readable detail for the failure." + "description": "Human-readable detail for display or troubleshooting; its wording is not stable, so do not parse it." } }, "required": [ @@ -11895,18 +12216,18 @@ }, "DashboardRuntimeDatasource": { "type": "object", - "description": "The datasource a runtime query was bound to.", + "description": "The datasource a runtime variable or query was bound to.", "properties": { "id": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "Datasource ID." + "description": "Datasource ID, as listed by the datasource list endpoint." }, "type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", - "description": "Datasource type identifier." + "description": "Datasource type identifier. Resolved queries and `query` variables only use `prometheus`, `mysql` or `loki`; the datasource chosen by a `datasource` variable can be any type identifier the variable was configured with." }, "name": { "type": "string", @@ -11921,12 +12242,12 @@ }, "DashboardResolvedVariable": { "type": "object", - "description": "One resolved variable. An unreachable datasource, a bad expression or an empty result leaves `candidates` incomplete and fills `error` instead of failing the request.", + "description": "One resolved variable. A failure (no selection and no default, a selection outside the candidates, an unresolved dependency, an unreachable datasource, an unusable query result) fills `error` and leaves `selection` out instead of failing the request.", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "Variable name." + "description": "Variable name, as defined in the dashboard or draft." }, "kind": { "type": "string", @@ -11942,7 +12263,7 @@ "items": { "$ref": "#/components/schemas/DashboardCandidate" }, - "description": "Resolved candidates, at most 1000." + "description": "Selectable options, at most 1000; an empty array when there are none or resolution failed. Order: `custom` keeps the definition order, `datasource` is sorted by name then ID, `query` is sorted by value." }, "selection": { "$ref": "#/components/schemas/DashboardSelection" @@ -11977,13 +12298,13 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections already made, keyed by variable name, at most 20 entries. Variables omitted here fall back to their stored defaults." + "description": "Selections already made, keyed by variable name, at most 20 entries. Variables without an entry fall back to their stored defaults; a name the dashboard does not define fails the call with HTTP 400.", + "maxProperties": 20 } }, "required": [ "dashboard_id", - "time", - "variables" + "time" ] }, "DashboardVariablesResolveResponse": { @@ -11993,7 +12314,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the dashboard the variables were resolved for, echoing the request." }, "revision": { "type": "integer", @@ -12030,7 +12351,7 @@ "ref_id": { "type": "string", "pattern": "^[A-Z]$", - "description": "Panel-local query reference." + "description": "Query reference within the panel: a single letter `A`–`Z`." }, "datasource": { "$ref": "#/components/schemas/DashboardRuntimeDatasource" @@ -12042,27 +12363,24 @@ "instant", "window" ], - "description": "Evaluation mode: `range` = a stepped time series; `instant` = a single point in time; `window` = raw rows inside a bounded time window." + "description": "Evaluation mode: `range` = a stepped time series; `instant` = a single point in time; `window` = rows inside a bounded time window. Prometheus and Loki queries use `range` or `instant`; MySQL queries use `window`." }, "expr": { "type": "string", - "description": "Expression with variable templates substituted." + "description": "Expression with variable templates substituted. Built-in time variables stay verbatim when the request set `preserve_builtin_variables` to `true`." }, "args": { "type": "object", "additionalProperties": { "type": "string" }, - "description": "Query arguments; empty object when none." + "description": "Query arguments; an empty object when none. Only Loki queries carry arguments: `loki.limit` (a decimal integer from 1 to 1000, the maximum number of log entries) and `loki.direction` (`latest` or `earliest`)." }, "min_step_seconds": { - "type": [ - "integer", - "null" - ], + "type": "integer", "format": "int64", "minimum": 1, - "description": "Minimum step in seconds; null when unset." + "description": "Minimum step in seconds from the panel query; omitted when unset." } }, "required": [ @@ -12075,12 +12393,12 @@ }, "DashboardResolvedPanelQueries": { "type": "object", - "description": "Per-panel resolution result. `state` is `success` when every query resolved, `partial` when some did and `error` when none did.", + "description": "Per-panel resolution result. `state` is `success` when every query resolved, `partial` when some did and `error` when none did. `error` describes only the first failure.", "properties": { "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Panel ID." + "description": "ID of the panel, echoing an entry of `panel_ids`." }, "state": { "type": "string", @@ -12089,14 +12407,14 @@ "partial", "error" ], - "description": "Aggregate state of the panel's queries: `success` = every query resolved; `partial` = some resolved; `error` = none resolved." + "description": "Resolution state of the panel's queries: `success` = every query resolved; `partial` = some resolved and some failed; `error` = none resolved, including a panel that does not exist." }, "queries": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardResolvedQuery" }, - "description": "Successfully resolved queries." + "description": "Queries that resolved successfully, in the panel's query order. Queries that failed are left out; empty array when none resolved." }, "error": { "$ref": "#/components/schemas/DashboardRuntimeError" @@ -12135,7 +12453,8 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections keyed by variable name, at most 20 entries." + "description": "Selections keyed by variable name, at most 20 entries. Variables without an entry fall back to their stored defaults; a name the dashboard does not define fails the call with HTTP 400.", + "maxProperties": 20 }, "max_data_points": { "type": [ @@ -12144,7 +12463,7 @@ ], "minimum": 2, "maximum": 5000, - "description": "Downsampling target used to compute the step and render the built-in time variables, 2–5000 points; omit or send null for the server default of 100." + "description": "Target maximum number of points per series, used to compute the step and render the built-in time variables. 2–5000; omit or send null for the default of 100." }, "preserve_builtin_variables": { "type": "boolean", @@ -12154,18 +12473,17 @@ "required": [ "dashboard_id", "panel_ids", - "time", - "variables" + "time" ] }, "DashboardQueriesResolveResponse": { "type": "object", - "description": "One entry per requested panel, in request order.", + "description": "Resolved queries of the requested panels, plus the effective variable selections they were resolved with. Nothing is executed.", "properties": { "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the dashboard the queries were resolved against, echoing the request." }, "revision": { "type": "integer", @@ -12181,14 +12499,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections that resolved successfully." + "description": "Effective selections of the variables that resolved successfully, keyed by variable name; variables that failed to resolve are left out." }, "panels": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardResolvedPanelQueries" }, - "description": "Per-panel results." + "description": "One entry per requested panel, in request order." } }, "required": [ @@ -12206,12 +12524,12 @@ "max_concurrency": { "type": "integer", "minimum": 1, - "description": "Concurrency cap applied to the panel's queries." + "description": "Maximum number of the panel's queries executed at the same time; fixed at 6." }, "execution_count": { "type": "integer", "minimum": 0, - "description": "Number of queries launched." + "description": "Number of queries that resolved successfully and were dispatched for execution; queries that failed to resolve are not counted." } }, "required": [ @@ -12221,12 +12539,12 @@ }, "DashboardPanelRunRef": { "type": "object", - "description": "Result of one query inside a panel run. The raw execution payload differs per datasource type and is passed through unmodified, so it is not schema-constrained here.", + "description": "Result of one query inside a panel run or preview. The raw execution payload differs per datasource type and is passed through unmodified, so it is not schema-constrained here.", "properties": { "ref_id": { "type": "string", "pattern": "^[A-Z]$", - "description": "Panel-local query reference." + "description": "Query reference within the panel: a single letter `A`–`Z`, as set in the panel's `queries`." }, "state": { "type": "string", @@ -12235,16 +12553,16 @@ "error", "incompatible" ], - "description": "Per-query execution state: `success` = the query executed; `error` = the query failed; `incompatible` = the datasource accepted the call but the query mode or field selection does not fit the datasource type." + "description": "Per-query state: `success` = the query ran and `execution` is present; `error` = the query could not be resolved or executed, or the run was cancelled or timed out, and `error` explains why; `incompatible` = the query ran, but its result does not fit the panel's visualization (for example a configured field is missing or not numeric), so `execution` is still present and `error` explains the mismatch." }, "child_request_id": { "type": "string", - "description": "Request ID of the underlying datasource execution; use it when tracing a single query." + "description": "Request ID of the underlying datasource execution; use it when tracing a single query. Absent when the query never reached the datasource." }, "execution": { "type": "object", "additionalProperties": true, - "description": "Datasource-specific execution payload, passed through unmodified." + "description": "Datasource-specific execution result, passed through unmodified. Present when `state` is `success` or `incompatible`; absent when `state` is `error`." }, "error": { "$ref": "#/components/schemas/DashboardRuntimeError" @@ -12257,7 +12575,7 @@ }, "DashboardPanelRunRequest": { "type": "object", - "description": "Execute one panel against the stored dashboard. Omit `revision` to run the current revision; send it to have stale responses rejected.", + "description": "Execute one panel of a stored dashboard. Omit `revision` (or send 0) to run the current revision; send it to have a stale call rejected. Text panels cannot be run.", "properties": { "dashboard_id": { "type": "string", @@ -12267,13 +12585,12 @@ "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Panel to execute." + "description": "ID of the panel to execute. It must belong to the dashboard, otherwise the call returns `TargetNotFound` (HTTP 404)." }, "revision": { "type": "integer", "format": "uint64", - "minimum": 1, - "description": "Revision guard; when set it must equal the current revision." + "description": "Revision guard. When set (non-zero) it must equal the dashboard's current revision, otherwise the call fails with `DashboardRevisionConflict` (HTTP 409). Omit or send 0 to skip the check." }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12283,7 +12600,8 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections keyed by variable name, at most 20 entries." + "description": "Selections keyed by variable name, at most 20 entries. Variables without an entry fall back to their stored defaults; a name the dashboard does not define fails the call with HTTP 400.", + "maxProperties": 20 }, "max_data_points": { "type": [ @@ -12292,29 +12610,28 @@ ], "minimum": 2, "maximum": 5000, - "description": "Downsampling target, 2–5000 points; omit or send null for the server default of 100." + "description": "Target maximum number of points per series for `range` queries; the server derives the query step from it. 2–5000; omit or send null for the default of 100." } }, "required": [ "dashboard_id", "panel_id", - "time", - "variables" + "time" ] }, "DashboardPanelRunResponse": { "type": "object", - "description": "Panel execution result. `run_state` aggregates the per-query states: `success` when all succeeded, `partial` when some did, otherwise `incompatible`, `cancelled` or `error`. The total response is capped at 8 MiB.", + "description": "Panel execution result. HTTP 200 is returned even when every query failed; read `run_state` and each ref's `state` and `error`. A response larger than 8 MiB is rejected with `EntityTooLarge` (HTTP 413) instead of being truncated.", "properties": { "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Dashboard ID." + "description": "ID of the dashboard that was run, echoing the request." }, "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Panel ID." + "description": "ID of the panel that was run, echoing the request." }, "revision": { "type": "integer", @@ -12331,7 +12648,7 @@ "cancelled", "error" ], - "description": "Aggregate state of the run: `success` = all queries succeeded; `partial` = some succeeded; `incompatible` = at least one query is incompatible with its datasource; `cancelled` = the run was cancelled; `error` = all queries failed." + "description": "Aggregate state of the run: `success` = every query succeeded; `partial` = at least one query succeeded and at least one did not; `cancelled` = no query succeeded and the client cancelled the request; `incompatible` = no query succeeded and at least one query ran but returned a result that does not fit the panel's visualization; `error` = no query succeeded and none is `incompatible` (also when the panel has no queries)." }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12341,14 +12658,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections that resolved successfully." + "description": "Effective selections of the variables that resolved successfully, keyed by variable name; variables that failed to resolve are left out." }, "refs": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardPanelRunRef" }, - "description": "One entry per query in the panel." + "description": "One entry per query of the panel, in the panel's query order. A query that failed to resolve appears with `state` `error`." }, "display": { "$ref": "#/components/schemas/DashboardVizConfig" @@ -12384,13 +12701,13 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Required for `existing`, forbidden for `new`." + "description": "Required for `existing`, forbidden for `new`. The caller must have access to the dashboard's folder." }, "folder_id": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "Required for `new`, forbidden for `existing`." + "description": "Required for `new`, forbidden for `existing`. Must be a folder the caller can access, otherwise the call returns `FolderNotFound` (HTTP 404)." } }, "required": [ @@ -12410,14 +12727,15 @@ "$ref": "#/components/schemas/DashboardVariable" }, "maxItems": 20, - "description": "Draft variables, at most 20." + "description": "Draft variables, at most 20. They are validated like a stored definition (names, dependencies, option limits) and must stay within 1 MiB." }, "selections": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections keyed by variable name, at most 20 entries." + "description": "Selections keyed by variable name, at most 20 entries. Variables without an entry fall back to their draft default; a name that is not in `variables` fails the call with HTTP 400.", + "maxProperties": 20 }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12426,7 +12744,6 @@ "required": [ "context", "variables", - "selections", "time" ] }, @@ -12439,14 +12756,14 @@ "items": { "$ref": "#/components/schemas/DashboardResolvedVariable" }, - "description": "Resolved variables." + "description": "Resolved variables, in the order of the draft `variables`." }, "selections": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Effective selections keyed by variable name." + "description": "Effective selections keyed by variable name; only variables that resolved successfully appear." } }, "required": [ @@ -12456,7 +12773,7 @@ }, "DashboardPanelPreviewRequest": { "type": "object", - "description": "Execute a draft panel inline, without saving a dashboard revision. Subject to the same 1 MiB definition-size ceiling.", + "description": "Execute a draft panel inline, without saving a dashboard revision. The draft `panel` and `variables` together must stay within 1 MiB, and the request body within 2 MiB.", "properties": { "context": { "$ref": "#/components/schemas/DashboardDraftContext" @@ -12470,14 +12787,15 @@ "$ref": "#/components/schemas/DashboardVariable" }, "maxItems": 20, - "description": "Draft variables the panel may reference." + "description": "Draft variables the panel may reference, at most 20. Required; the panel's queries can only use variables listed here." }, "selections": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections keyed by variable name." + "description": "Selections keyed by variable name, at most 20 entries. Variables without an entry fall back to their draft default.", + "maxProperties": 20 }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12489,25 +12807,24 @@ ], "minimum": 2, "maximum": 5000, - "description": "Downsampling target, 2–5000 points." + "description": "Target maximum number of points per series for `range` queries; the server derives the query step from it. 2–5000; omit or send null for the default of 100." } }, "required": [ "context", "panel", "variables", - "selections", "time" ] }, "DashboardPanelPreviewResponse": { "type": "object", - "description": "Draft panel execution result. Same shape as a stored panel run, minus the dashboard identity.", + "description": "Draft panel execution result. Same shape as a stored panel run, minus `dashboard_id` and `revision`. HTTP 200 is returned even when every query failed; a response larger than 8 MiB is rejected with `EntityTooLarge` (HTTP 413).", "properties": { "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Panel ID." + "description": "ID of the draft panel, echoing `panel.id` from the request." }, "run_state": { "type": "string", @@ -12518,7 +12835,7 @@ "cancelled", "error" ], - "description": "Aggregate state of the run: `success` = all queries succeeded; `partial` = some succeeded; `incompatible` = at least one query is incompatible with its datasource; `cancelled` = the run was cancelled; `error` = all queries failed." + "description": "Aggregate state of the run: `success` = every query succeeded; `partial` = at least one query succeeded and at least one did not; `cancelled` = no query succeeded and the client cancelled the request; `incompatible` = no query succeeded and at least one query ran but returned a result that does not fit the panel's visualization; `error` = no query succeeded and none is `incompatible` (also when the panel has no queries)." }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12528,14 +12845,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "Selections that resolved successfully." + "description": "Effective selections of the variables that resolved successfully, keyed by variable name; variables that failed to resolve are left out." }, "refs": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardPanelRunRef" }, - "description": "One entry per query in the panel." + "description": "One entry per query of the panel, in the panel's query order. A query that failed to resolve appears with `state` `error`." }, "display": { "$ref": "#/components/schemas/DashboardVizConfig" @@ -12556,12 +12873,12 @@ }, "FolderItem": { "type": "object", - "description": "A monitor folder (监控节点). Folders form a tree; `parent_path` is the comma-separated ancestor ID list, so the caller can rebuild the tree and search it client-side.", + "description": "A monitor folder. Folders form a tree; `parent_path` is the comma-separated ancestor ID list, so the caller can rebuild the tree and search it client-side.", "properties": { "id": { "type": "integer", "format": "uint64", - "description": "Folder ID." + "description": "Folder ID. Pass it as `id` to update, move, or delete the folder, as `parent_id` or `dest_parent_id` to nest folders under it, and as `folder_id` on alert rules and dashboards." }, "account_id": { "type": "integer", @@ -12580,7 +12897,7 @@ "team_id": { "type": "integer", "format": "uint64", - "description": "Team the folder is scoped to; 0 when account-wide." + "description": "ID of the team the folder belongs to; 0 when it has no team. Members of the team can see and modify the folder." }, "name": { "type": "string", @@ -12593,7 +12910,7 @@ "creator_id": { "type": "integer", "format": "uint64", - "description": "Member ID of the creator." + "description": "Member ID of the creator; the creator can always see and modify the folder." }, "creator_name": { "type": "string", @@ -12602,7 +12919,7 @@ "updater_id": { "type": "integer", "format": "uint64", - "description": "Member ID of the last updater." + "description": "Member ID of the last updater. Updates and moves both set it." }, "updater_name": { "type": "string", @@ -12611,12 +12928,12 @@ "created_at": { "type": "integer", "format": "int64", - "description": "Unix timestamp in seconds." + "description": "Creation time as a Unix timestamp in seconds." }, "updated_at": { "type": "integer", "format": "int64", - "description": "Unix timestamp in seconds." + "description": "Time of the last update or move as a Unix timestamp in seconds." } }, "required": [ @@ -12637,26 +12954,26 @@ }, "FolderCreateRequest": { "type": "object", - "description": "Monitor folder request.", + "description": "Request to create a monitor folder.", "properties": { "name": { "type": "string", - "description": "Folder name; cannot contain a period, slash, or comma.", + "description": "Folder name; required, and must not contain a period (`.`), slash (`/`), or comma (`,`).", "minLength": 1 }, "note": { "type": "string", - "description": "Free-form note; omitted or empty clears the note on update." + "description": "Free-form note. Empty when omitted." }, "parent_id": { "type": "integer", - "description": "Parent folder ID; 0 or omitted creates a root folder.", + "description": "ID of the parent folder; 0 or omitted creates a root folder. The caller must be allowed to modify the parent.", "format": "uint64", "minimum": 0 }, "team_id": { "type": "integer", - "description": "Team ID; 0 means account-wide. Omitted on update resets to 0.", + "description": "ID of the team the folder belongs to; 0 or omitted means no team. Members of the team can see and modify the folder and everything below it.", "format": "uint64", "minimum": 0 } @@ -12667,26 +12984,26 @@ }, "FolderUpdateRequest": { "type": "object", - "description": "Monitor folder request.", + "description": "Request to update a monitor folder. Editable fields are replaced as a whole.", "properties": { "id": { "type": "integer", - "description": "Folder ID.", + "description": "ID of the folder to update, from `/monit/folder/list` or the create response.", "format": "uint64", "minimum": 1 }, "name": { "type": "string", - "description": "Folder name; cannot contain a period, slash, or comma.", + "description": "New folder name; required, and must not contain a period (`.`), slash (`/`), or comma (`,`).", "minLength": 1 }, "note": { "type": "string", - "description": "Free-form note; omitted or empty clears the note on update." + "description": "New note. Omitted or empty clears the note." }, "team_id": { "type": "integer", - "description": "Team ID; 0 means account-wide. Omitted on update resets to 0.", + "description": "New team ID; 0 or omitted removes the team assignment.", "format": "uint64", "minimum": 0 } @@ -12698,17 +13015,17 @@ }, "FolderMoveRequest": { "type": "object", - "description": "Monitor folder request.", + "description": "Request to move a monitor folder and its descendants.", "properties": { "id": { "type": "integer", - "description": "Folder ID.", + "description": "ID of the folder to move, from `/monit/folder/list`.", "format": "uint64", "minimum": 1 }, "dest_parent_id": { "type": "integer", - "description": "Destination parent folder ID; required even when 0 to move to the root.", + "description": "ID of the new parent folder; send 0 to move to the root. The field cannot be omitted. Must differ from `id` and must not be a descendant of the folder.", "format": "uint64", "minimum": 0 } @@ -12720,11 +13037,11 @@ }, "FolderDeleteRequest": { "type": "object", - "description": "Monitor folder request.", + "description": "Request to delete a monitor folder.", "properties": { "id": { "type": "integer", - "description": "Folder ID.", + "description": "ID of the folder to delete, from `/monit/folder/list`. The folder must be empty.", "format": "uint64", "minimum": 1 } @@ -12739,13 +13056,13 @@ "properties": { "folder_id": { "type": "integer", - "description": "Folder ID.", + "description": "ID of the folder this entry describes; matches `id` in `/monit/folder/list`.", "format": "uint64", "minimum": 0 }, "has_issue": { "type": "boolean", - "description": "Whether this folder or a visible descendant has active alerts or rule runtime issues." + "description": "`true` when a rule in this folder or in any descendant has an active alert or a runtime problem (`runtime_state` of `offline`, `abnormal`, `stale`, or `no_datasource`). Rules in folders the caller cannot read are not counted." } }, "required": [ @@ -12759,7 +13076,7 @@ "properties": { "items": { "type": "array", - "description": "Folder health summaries.", + "description": "One health entry per folder visible to the caller, sorted by `folder_id`.", "items": { "$ref": "#/components/schemas/FolderHealthItem" } diff --git a/api-reference/monitors.openapi.zh.json b/api-reference/monitors.openapi.zh.json index e51b3412b..283a28247 100644 --- a/api-reference/monitors.openapi.zh.json +++ b/api-reference/monitors.openapi.zh.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "Flashduty 开放 API", - "description": "Flashduty 事件管理平台的公开 HTTP API —— 覆盖故障、通知模板、协作空间、值班排班、监控、RUM、以及平台管理。每次调用都需在 query 中携带 `app_key`,该 key 在 Flashduty 控制台 账户 → APP Key 中签发。所有响应使用统一结构:成功时为 `{ request_id, data }`,失败时为 `{ request_id, error }`。", + "description": "Flashduty 事件管理平台的公开 HTTP API —— 覆盖故障、通知模板、协作空间、值班排班、监控、RUM、以及平台管理。每次调用都需在 query 中携带 `app_key`,该 key 在 Flashduty 控制台 我的 → APP Key 中创建(也可放在请求头 `Fd-App-Key` 中)。所有响应使用统一结构:成功时为 `{ request_id, data }`,失败时为 `{ request_id, error }`。", "version": "1.0.0" }, "servers": [ @@ -52,7 +52,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**(`monit`) |\n\n## 使用说明\n\n- 每一项为一次历史快照:`num` 为 `clock`(Unix 时间戳,秒)时刻的规则总数。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **概览查看**(`monit`) |\n\n## 使用说明\n\n- 每一项为一次历史快照:`num` 为 `clock`(Unix 时间戳,秒)时刻账户下告警规则的总数(含启用与禁用的规则)。\n- 大约每 12 小时记录一次快照(每小时运行的任务在最近 12 小时内没有快照时补记一条)。返回全部快照,按时间从早到晚排列;尚未记录任何快照时返回空数组。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-read-counter-total", "metadata": { "sidebarTitle": "查看规则数量时序" @@ -83,7 +83,13 @@ "data": [ { "id": 1, - "account_id": 10023, + "account_id": 888, + "num": 48, + "clock": 1711956000 + }, + { + "id": 2, + "account_id": 888, "num": 50, "clock": 1712000000 } @@ -98,6 +104,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -122,12 +131,12 @@ "post": { "operationId": "monit-datasource-write-create", "summary": "创建数据源", - "description": "创建新的监控数据源,`payload` 中须包含对应类型的配置块。 支持诊断类型 redis_node、redis_sentinel、mongodb_mongod、mongodb_mongos 和 kafka;enabled 与 alerting_enabled 相互独立。", + "description": "创建一个监控数据源(支持 15 种类型),并将其绑定到某个 Monitors edge 集群。", "tags": [ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源管理**(`monit`) |\n\n## 使用说明\n\n- `type_ident` 必须为以下之一:`prometheus`、`loki`、`mysql`、`oracle`、`postgres`、`clickhouse`、`elasticsearch`、`sls`、`tencent_cls`、`victorialogs`、`redis_node`、`redis_sentinel`、`mongodb_mongod`、`mongodb_mongos`、`kafka`。\n- `edge_cluster_name` 指定使用该数据源进行规则评估的 Monitors Edge 集群。\n- 对于 `elasticsearch`,`payload.elasticsearch.deployment` 须设为 `cloud` 或 `self-managed`。\n- 每次调用都会记录到账户审计日志,仅通过凭据字段配置连接凭据。\n\n完整支持类型与凭据行为见请求/响应 Schema。仅诊断类型不能启用告警。创建时省略 enabled 默认为 true,更新时省略保留当前值;enabled 或 alerting_enabled 的显式 null 非法。诊断密码及 Kafka 私钥在响应中省略,环境变量引用除外;更新时省略秘密字段保留原值,空字符串清除。其他数据源凭据可能返回,应作为敏感数据处理。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **数据源管理**(`monit`) |\n\n## 使用说明\n\n- `type_ident` 必须为以下之一:`prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。后五种(`redis_node`、`redis_sentinel`、`mongodb_mongod`、`mongodb_mongos`、`kafka`)仅用于诊断,不能评估告警,因此 `alerting_enabled` 不能为 `true`。\n- `name` 在账户内唯一(不区分类型),重名时返回 `InvalidParameter`。\n- `edge_cluster_name` 必须是账户下已存在的 Monitors edge 集群;该集群负责评估规则并执行该数据源的查询。\n- 类型专属配置放在 `payload.` 中。`elasticsearch` 必须设置 `payload.elasticsearch.deployment`(`cloud` 或 `self-managed`)。`tencent_cls` 要求集群内所有 edge 实例均为 Monitors edge v0.66.0 或更高版本。\n- 省略 `enabled` 时默认为 `true`;省略 `alerting_enabled` 时,告警类默认 `true`,仅诊断类默认 `false`。两者显式传 `null` 都会被拒绝。\n- `manage_team_id` 和 `readonly_team_ids` 用于限制谁能管理或查询该数据源;两者都省略则对所有成员开放。\n- 响应会原样返回非诊断类型的凭据(例如 Prometheus 的 Basic Auth 密码);诊断类型的密码和 Kafka 私钥仅在它们是 `${env:NAME}` 引用时才返回。请将响应视为敏感信息。\n- 每次调用都会记录到账户审计日志。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-write-create", "metadata": { "sidebarTitle": "创建数据源" @@ -157,12 +166,26 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "id": 10, + "account_id": 10023, "type_ident": "prometheus", "name": "Prometheus Prod", "enabled": true, + "note": "Production Prometheus", + "address": "http://prometheus.example.com:9090", + "payload": { + "prometheus": { + "basic_auth_enabled": false, + "basic_auth_username": "", + "basic_auth_password": "", + "tls_skip_verify": false + } + }, "edge_cluster_name": "default", "updated_at": 1712000000, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001 } } } @@ -174,6 +197,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -209,12 +235,12 @@ "post": { "operationId": "monit-datasource-write-update", "summary": "更新数据源", - "description": "更新已有数据源,需提供 `id` 及待修改的字段。 支持诊断类型 redis_node、redis_sentinel、mongodb_mongod、mongodb_mongos 和 kafka;enabled 与 alerting_enabled 相互独立。", + "description": "按 ID 更新数据源,整体替换其名称、备注、地址、payload 和 edge 集群。", "tags": [ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源管理**(`monit`) |\n\n## 使用说明\n\n- 每次调用都会记录到账户审计日志,仅通过凭据字段配置连接凭据。\n\n完整支持类型与凭据行为见请求/响应 Schema。仅诊断类型不能启用告警。创建时省略 enabled 默认为 true,更新时省略保留当前值;enabled 或 alerting_enabled 的显式 null 非法。诊断密码及 Kafka 私钥在响应中省略,环境变量引用除外;更新时省略秘密字段保留原值,空字符串清除。其他数据源凭据可能返回,应作为敏感数据处理。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **数据源管理**(`monit`) |\n\n## 使用说明\n\n- 这是整体替换而非局部更新:每次调用都要发送 `type_ident`、`name`、`edge_cluster_name`、`payload`,以及 `address`(`cloud` 部署的 Elasticsearch 除外)。`note`、`address`、`payload` 会覆盖已保存的值,因此省略 `note` 会将其清空。\n- 省略 `enabled`、`alerting_enabled`、`manage_team_id`、`readonly_team_ids` 时保持原值。`enabled` 或 `alerting_enabled` 传 `null` 会被拒绝;两个团队字段传 `null` 表示清除。\n- 密钥:诊断类型省略密码(以及 Kafka 的 `tls_key`)表示保留已保存的值,传空字符串表示清除;`tencent_cls` 省略或传空的 `secret_key` 表示保留已保存的密钥;其他类型需要重新发送凭据。\n- 将 `enabled` 或 `alerting_enabled` 设为 `false`,或修改 `type_ident`、`edge_cluster_name`,会关闭使用该数据源的规则上的未恢复告警;重命名时,会关闭 `ds_list` 名称模式不再匹配新名称的规则上的未恢复告警。\n- 只要仍有已启用的告警规则选中该数据源,关闭 `alerting_enabled` 会返回 HTTP 409 `UndonedOrderExist`。\n- 只有账户所有者、管理员、创建者和负责团队成员可以更新数据源(未设置负责团队时,拥有该权限的调用方均可);其他人返回 `AccessDenied`。ID 不存在或属于其他账户时返回 `ResourceNotFound`。\n- 每次调用都会记录到账户审计日志。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-write-update", "metadata": { "sidebarTitle": "更新数据源" @@ -244,12 +270,26 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "id": 10, + "account_id": 10023, "type_ident": "prometheus", "name": "Prometheus Prod v2", "enabled": true, + "note": "Updated", + "address": "http://prometheus-v2.example.com:9090", + "payload": { + "prometheus": { + "basic_auth_enabled": false, + "basic_auth_username": "", + "basic_auth_password": "", + "tls_skip_verify": false + } + }, "edge_cluster_name": "default", "updated_at": 1712100000, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001 } } } @@ -261,6 +301,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -302,7 +345,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 如果目标文件夹中已存在同名规则,该规则会被跳过;请检查每条结果的 `message` 以识别冲突。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `dest_folder_id` 必须是已存在的文件夹,且调用者须对该文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员);否则整个调用返回 `AccessDenied`,不会移动任何规则。\n- 结果按请求顺序为每个 ID 返回一项。移动成功的规则 `message` 为本地化的成功文案(`Move successfully` / `移动成功`);未移动的规则保留在原文件夹,`message` 为错误信息。\n- 目标文件夹已有同名规则、调用者对规则当前所在文件夹无管理权限,或 ID 不存在(此时 `name` 为 `id: `)时,该规则不会被移动。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-write-move", "metadata": { "sidebarTitle": "移动告警规则到文件夹" @@ -333,7 +376,11 @@ "data": [ { "name": "CPU High", - "message": "" + "message": "移动成功" + }, + { + "name": "Disk High", + "message": "alert rule name already exists in this folder" } ] } @@ -346,6 +393,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -376,12 +426,12 @@ "post": { "operationId": "monit-rule-read-audit-detail", "summary": "查看规则审计快照", - "description": "返回审计记录(包含 `content` 字段,即该时间点规则配置的 JSON 字符串快照)。", + "description": "返回告警规则的一条审计记录,包含保存在 `content` 中的规则快照。", "tags": [ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**(`monit`) |\n\n## 使用说明\n\n- 传入来自 `POST /monit/rule/audits` 的审计记录 `id`(非规则 `id`)。\n- `content` 为 JSON 字符串,解析后可获得完整的规则快照。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 任意有效 `app_key` 均可调用 |\n\n## 使用说明\n\n- 传入来自 `POST /monit/rule/audits` 的审计记录 `id`(非规则 `id`)。ID 不存在时返回 `InvalidParameter`(`alert rule audit not found`)。\n- `content` 为 JSON 字符串,解析后可获得规则快照;其结构取决于写入该记录的操作(见下方 `content` 字段说明)。\n- 调用者须对规则所在文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员),否则返回 `AccessDenied`。规则被删除后其审计记录无法再读取,调用返回 `InvalidParameter`(`alert rule not found`)。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-read-audit-detail", "metadata": { "sidebarTitle": "查看规则审计快照" @@ -411,13 +461,13 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "id": 9001, - "account_id": 10023, + "account_id": 888, "alert_rule_id": 50001, "action": "update", - "content": "{\"id\":50001,\"name\":\"CPU High\"}", - "creator_id": 80011, - "creator_name": "Alice", - "created_at": 1712000000 + "content": "{\"id\":50001,\"account_id\":888,\"folder_id\":100,\"name\":\"CPU High\",\"enabled\":true,\"updated_at\":1712003600}", + "creator_id": 66, + "creator_name": "zhangsan", + "created_at": 1712003600 } } } @@ -429,6 +479,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -455,12 +508,12 @@ "post": { "operationId": "monit-datasource-write-delete", "summary": "删除数据源", - "description": "通过 ID 删除数据源。引用该数据源的告警规则不会被阻塞:该数据源会从规则的监控范围中移除,规则上相关的未恢复告警会自动关闭。", + "description": "按 ID 删除数据源;引用它的告警规则不会被阻止。", "tags": [ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源管理**(`monit`) |\n\n## 使用说明\n\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **数据源管理**(`monit`) |\n\n## 使用说明\n\n- 引用该数据源的告警规则不会被阻止,也不会被修改;规则上该数据源的未恢复告警会自动关闭。\n- 删除不存在的 ID 会直接成功(无任何操作);属于其他账户的 ID 返回 `ResourceNotFound`。\n- 只有账户所有者、管理员、创建者和负责团队成员可以删除数据源(未设置负责团队时,拥有该权限的调用方均可);其他人返回 `AccessDenied`。\n- 每次调用都会记录到账户审计日志。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-write-delete", "metadata": { "sidebarTitle": "删除数据源" @@ -499,6 +552,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -530,7 +586,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **30 次/分钟**;**5 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **100 次/分钟**;**5 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 按顺序逐个处理 ID,遇到第一个错误即停止;错误前已删除的规则不会恢复,请排除原因后重新提交剩余 ID。\n- 不存在的 ID 会被跳过,不报错。每条被删除规则的活跃告警会被清理。\n- `ids` 至少包含一个 ID。调用者须对每条规则所在的文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员),否则返回 `AccessDenied`。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-write-delete-batch", "metadata": { "sidebarTitle": "批量删除告警规则" @@ -569,6 +625,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -603,7 +662,7 @@ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- `id` 指定的数据源类型必须为 `sls`。\n- 使用 `query` 按名称前缀过滤项目,使用 `offset` 和 `size` 分页。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- `id` 指定的数据源类型必须为 `sls`,其他类型返回 `InvalidParameter`。\n- 使用 `query` 过滤项目列表,使用 `offset` 和 `size` 分页;`count` 为当前页项目数,`total` 为满足过滤条件的项目总数。\n- 请求会转发给该数据源所属的 Monitors edge 集群,由 edge 使用已保存的凭据调用阿里云,30 秒超时。该集群没有在线的 edge 实例时返回 `InvalidParameter`;edge 版本不支持元数据发现时返回 HTTP 503 `ServiceUnavailable`。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-read-sls-projects", "metadata": { "sidebarTitle": "查询 SLS 项目列表" @@ -665,6 +724,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -699,7 +761,7 @@ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- `id` 指定的数据源类型必须为 `sls`。\n- 通过 `project` 指定要列出日志库的 SLS 项目。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- `id` 指定的数据源类型必须为 `sls`,其他类型返回 `InvalidParameter`。\n- 通过 `project` 指定要列出日志库的 SLS 项目;使用 `offset` 和 `size` 分页。响应是日志库名称组成的数组。\n- 请求会转发给该数据源所属的 Monitors edge 集群,由 edge 使用已保存的凭据调用阿里云,30 秒超时。该集群没有在线的 edge 实例时返回 `InvalidParameter`;edge 版本不支持元数据发现时返回 HTTP 503 `ServiceUnavailable`。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-read-sls-logstores", "metadata": { "sidebarTitle": "查询 SLS 日志库列表" @@ -741,6 +803,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -770,12 +835,12 @@ "post": { "operationId": "monit-datasource-read-info", "summary": "查看数据源详情", - "description": "通过 ID 获取单个数据源的完整信息,包括 `payload` 配置及其中配置的连接与鉴权信息;请将该响应视为敏感信息,避免记录或转发。 支持诊断类型 redis_node、redis_sentinel、mongodb_mongod、mongodb_mongos 和 kafka;enabled 与 alerting_enabled 相互独立。", + "description": "按 ID 返回单个数据源,包含完整的 `payload` 配置。", "tags": [ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n完整支持类型与凭据行为见请求/响应 Schema。仅诊断类型不能启用告警。创建时省略 enabled 默认为 true,更新时省略保留当前值;enabled 或 alerting_enabled 的显式 null 非法。诊断密码及 Kafka 私钥在响应中省略,环境变量引用除外;更新时省略秘密字段保留原值,空字符串清除。其他数据源凭据可能返回,应作为敏感数据处理。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 需要该数据源的管理权限(见 `manage_team_id`);只有查询权限的成员返回 `AccessDenied`。需要查看自己可查询的数据源时请使用 `/monit/datasource/list`。\n- 响应属于敏感信息:`payload` 包含连接配置,非诊断类型的凭据会原样返回;诊断类型的密码和 Kafka 私钥仅在是 `${env:NAME}` 引用时才返回;`tencent_cls` 的 `secret_key` 返回空字符串,除非它是 `${env:NAME}` 引用。\n- ID 不存在或属于其他账户时返回 `ResourceNotFound`。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-read-info", "metadata": { "sidebarTitle": "查看数据源详情" @@ -821,7 +886,10 @@ }, "edge_cluster_name": "default", "updated_at": 1712000000, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001 } } } @@ -833,6 +901,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -864,7 +935,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**(`monit`) |", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 任意有效 `app_key` 均可调用 |\n\n## 使用说明\n\n- 记录按时间倒序排列,不含 `content`;如需查看快照,请调用 `POST /monit/rule/audit/detail`。\n- 每次创建、整体更新、字段批量更新和移动都会写入一条记录。删除规则不会写入记录,且规则删除后无法再列出其历史,调用返回 `InvalidParameter`(`alert rule not found`)。\n- 调用者须对规则所在文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员),否则返回 `AccessDenied`。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-read-audits", "metadata": { "sidebarTitle": "查询规则变更历史" @@ -895,11 +966,20 @@ "data": [ { "id": 9001, - "account_id": 10023, + "account_id": 888, "alert_rule_id": 50001, "action": "update", - "creator_id": 80011, - "creator_name": "Alice", + "creator_id": 66, + "creator_name": "zhangsan", + "created_at": 1712003600 + }, + { + "id": 8990, + "account_id": 888, + "alert_rule_id": 50001, + "action": "create", + "creator_id": 66, + "creator_name": "zhangsan", "created_at": 1712000000 } ] @@ -913,6 +993,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -944,7 +1027,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 删除规则时会同时清理该规则的活跃告警。\n- 删除不存在的 ID 也会成功并返回空 `data`,因此可以安全重试。\n- 调用者须对规则所在文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员),否则返回 `AccessDenied`。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-write-delete", "metadata": { "sidebarTitle": "删除告警规则" @@ -983,6 +1066,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1009,12 +1095,12 @@ "post": { "operationId": "monit-rule-read-list", "summary": "查询告警规则列表", - "description": "返回指定文件夹下所有告警规则的基础信息。如需完整规则详情,请调用 `POST /monit/rule/v2/info`。", + "description": "返回指定文件夹下告警规则的基础信息;如需完整配置,请调用 `POST /monit/rule/v2/info`。", "tags": [ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**(`monit`) |\n\n## 使用说明\n\n- 将 `folder_id` 设为 `0` 可列出当前用户有权查看的所有文件夹下的规则。\n- `triggered` 字段表示该规则当前是否有活跃告警。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**或**告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `folder_id` 必须是已存在的文件夹:传 `0` 或不存在的 ID 返回 `InvalidParameter`;调用者对该文件夹无管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员)时返回 `AccessDenied`。不支持跨文件夹列出整个账户的规则。\n- 默认只返回直接位于该文件夹下的规则,按名称排序,并填充 `active_alert_count` 与 `runtime_state`。\n- `include_descendants` 为 `true` 时会搜索该文件夹及其所有子孙文件夹,按名称排序最多返回 `limit` 条;此时只填充 `id`、`folder_id`、`name`,其余字段为零值(`labels` 为 `null`,不返回 `runtime_state`)。\n- 当且仅当 `active_alert_count > 0` 时 `triggered` 为 `true`。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-read-list", "metadata": { "sidebarTitle": "查询告警规则列表" @@ -1045,12 +1131,25 @@ "data": [ { "id": 50001, + "account_id": 888, "folder_id": 100, "name": "CPU High", + "labels": { + "team": "sre" + }, "ds_type": "prometheus", "enabled": true, - "triggered": true, + "debug_log_enabled": false, + "cron_pattern": "0 * * * * *", + "timezone": "Asia/Shanghai", + "delay_seconds": 0, + "creator_id": 66, + "creator_name": "zhangsan", + "updater_id": 66, + "updater_name": "zhangsan", "created_at": 1710000000, + "updated_at": 1712000000, + "triggered": true, "active_alert_count": 2, "runtime_state": "normal" } @@ -1065,6 +1164,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1091,12 +1193,12 @@ "post": { "operationId": "monit-datasource-read-list", "summary": "查询数据源列表", - "description": "返回当前账户下的所有数据源,可通过 `type_ident` 过滤类型。 支持诊断类型 redis_node、redis_sentinel、mongodb_mongod、mongodb_mongos 和 kafka;enabled 与 alerting_enabled 相互独立。", + "description": "列出账户下调用方有权查询的数据源,可按类型或名称精确过滤。", "tags": [ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 省略 `type_ident` 可返回所有类型的数据源。\n- 列表响应中不返回敏感凭证字段(密码、密钥)。\n\n完整支持类型与凭据行为见请求/响应 Schema。仅诊断类型不能启用告警。创建时省略 enabled 默认为 true,更新时省略保留当前值;enabled 或 alerting_enabled 的显式 null 非法。诊断密码及 Kafka 私钥在响应中省略,环境变量引用除外;更新时省略秘密字段保留原值,空字符串清除。其他数据源凭据可能返回,应作为敏感数据处理。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 省略 `type` 和 `name` 时返回你有权查询的所有数据源;`type`、`name` 均为精确匹配。无法识别的 `type` 返回空数组。结果不分页。\n- 只返回调用方有权查询的数据源(见 `readonly_team_ids`);每项带有 `my_perm`(`manage` 或 `readonly`)。\n- 列表项中的 `payload` 恒为 `null`。如需读取自己可管理的数据源的配置,请使用 `/monit/datasource/info`。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-read-list", "metadata": { "sidebarTitle": "查询数据源列表" @@ -1133,10 +1235,14 @@ "enabled": true, "note": "Production Prometheus", "address": "http://prometheus.example.com:9090", + "payload": null, "edge_cluster_name": "default", "updated_at": 1712000000, - "payload": null, - "alerting_enabled": true + "alerting_enabled": true, + "manage_team_id": null, + "readonly_team_ids": null, + "creator_id": 20001, + "my_perm": "manage" } ] } @@ -1149,6 +1255,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1175,12 +1284,12 @@ "post": { "operationId": "monit-rule-write-fields-update", "summary": "批量更新规则字段", - "description": "一次性更新多条告警规则的特定字段,仅应用 `fields` 列表中指定的字段。", + "description": "在一次调用中为多条告警规则更新 `fields` 中列出的字段。", "tags": [ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 在 `fields` 数组中指定要更新的字段名,如 `[\"enabled\", \"channel_ids\"]`。\n- 仅更新指定字段,其他字段保持不变。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- 每个列出的字段取同名请求字段的值;列出但未传值的字段会被设为零值(例如 `fields` 包含 `labels` 却既不传 `labels` 也不传 `labels_patch`,会清空全部标签)。未列出的字段保持原值。\n- `fields` 中出现未知字段名、传入 `labels_patch` / `annotations_patch` 但 `fields` 未包含对应字段,或同时传入 `labels` 与 `labels_patch`(`annotations` 与 `annotations_patch` 同理)时,整个调用返回 `InvalidParameter`。\n- 规则逐条更新,结果为每个 ID 返回一项:成功时 `message` 为空,否则为该规则的错误信息(校验失败、对其所在文件夹无权限,或 ID 不存在,此时 `name` 为 `id: `)。\n- 将 `enabled` 设为 `false` 会清理这些规则的活跃告警。除非本次调用只是停用规则(`fields` 恰好为 `[\"enabled\"]` 且 `enabled: false`),否则账户规则数超出告警规则 License 上限时返回 `AccessDenied`,且非管理员调用者须对每条规则选中的所有数据源具备只读权限。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-write-fields-update", "metadata": { "sidebarTitle": "批量更新规则字段" @@ -1228,6 +1337,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1261,12 +1373,12 @@ "post": { "operationId": "monit-rule-read-counter-channel", "summary": "按协作空间查询规则统计", - "description": "返回一个对象,key 为协作空间名称,value 为将告警路由到该协作空间的规则数量。若协作空间名称无法解析,则以协作空间 ID(字符串形式)作为 key。", + "description": "按协作空间名称返回将告警路由到各协作空间的告警规则数量。", "tags": [ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**(`monit`) |", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **概览查看**(`monit`) |\n\n## 使用说明\n\n- 仅统计 `channel_ids` 非空的规则;一条规则路由到多个协作空间时,会在每个协作空间下各计一次。\n- 协作空间 ID 无法解析为名称时,以该 ID 的字符串形式作为 key;同名的协作空间会合并到同一个 key。\n- 没有任何规则路由到协作空间时返回空对象 `{}`。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-read-counter-channel", "metadata": { "sidebarTitle": "按协作空间查询规则统计" @@ -1307,6 +1419,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1336,7 +1451,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**(`monit`) |\n\n## 使用说明\n\n- `id` 必填且不能为 `0`,否则返回 `InvalidParameter`。\n- 规则不存在时返回 `InvalidParameter`(`alert rule not found`)。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**或**告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `id` 必填且不能为 `0`,否则返回 `InvalidParameter`。\n- 规则不存在或属于其他账户时返回 `InvalidParameter`(`alert rule not found`)。\n- 不做文件夹级权限校验:具备上述权限的调用者可读取账户内的任意规则。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-read-info-v2", "metadata": { "sidebarTitle": "获取告警规则详情 V2" @@ -1378,6 +1493,7 @@ "enabled": true, "debug_log_enabled": false, "rule_configs": { + "relate_queries": [], "queries": [ { "name": "A", @@ -1438,6 +1554,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1469,7 +1588,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `name`、`ds_type`、`enabled`、`cron_pattern` 和 `rule_configs.queries` 为必填项;`ds_list`(支持通配符)或 `ds_ids` 必须有一个非空。\n- `enabled` 必须显式传入(包括 `false`),缺失时返回 `InvalidParameter`。\n- `id`、`account_id`、`creator_*`、`updater_*`、`created_at`、`updated_at` 由服务端赋值,客户端传入将被忽略。\n- `name` 在 `folder_id` 内必须唯一;重名会返回 `InvalidParameter`。\n- `channel_ids` 可为空,告警将通过全局集成路由。\n- 请求体容忍额外的未知字段(向前兼容),未知字段会被忽略。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `folder_id`、`name`、`ds_type`、`enabled`、`cron_pattern` 和 `rule_configs.queries` 为必填项;`ds_list`(支持通配符)与 `ds_ids` 至少一个非空。\n- `enabled` 必须显式传入(包括 `false`),缺失时返回 `InvalidParameter`。\n- `folder_id` 必须是已存在的文件夹(否则返回 `InvalidParameter`),且调用者须对该文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员)(否则返回 `AccessDenied`)。\n- `name` 在 `folder_id` 内必须唯一;重名会返回 `InvalidParameter`。\n- `enabled` 为 `true` 时,`ds_type` 必须是支持告警的数据源类型,且 `ds_ids` 中的每个 ID 都必须是已启用并开启告警的数据源,否则返回 `InvalidParameter`。\n- 账户所有者和管理员以外的调用者,须对 `ds_ids` 中列出的、以及 `ds_list` 当前匹配到的每个数据源具备只读权限,否则返回 `AccessDenied`(`no permission to reference datasource \"\"`)。\n- 创建后若超出账户的告警规则 License 上限,调用返回 `AccessDenied`。\n- `id`、`account_id`、`creator_*`、`updater_*`、`created_at`、`updated_at` 由服务端赋值,客户端传入将被忽略。\n- `channel_ids` 可为空,告警将通过全局集成路由。\n- 请求体不得超过 1 MiB,超出时返回 HTTP 413(`EntityTooLarge`)。请求体中额外的未知字段会被忽略(向前兼容)。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-write-create-v2", "metadata": { "sidebarTitle": "创建告警规则 V2" @@ -1511,6 +1630,7 @@ "enabled": true, "debug_log_enabled": false, "rule_configs": { + "relate_queries": [], "queries": [ { "name": "A", @@ -1571,6 +1691,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1629,7 +1752,7 @@ "Monitors/告警规则" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `id` 必填且对应规则必须已存在,否则返回 `InvalidParameter`。\n- 本接口为全量字段替换语义:除下列例外外,未传入的字段按零值保存,建议先调用 `/monit/rule/v2/info` 获取完整配置后再修改。\n- `enabled` 必须显式传入(包括 `false`),缺失时返回 `InvalidParameter`;更新为 `false` 时服务端会清理该规则的活跃告警。\n- `investigation_targets` 为例外:省略时保留原配置,传 `[]` 清空,传值则整体替换。\n- `folder_id` 不可通过本接口修改,调整文件夹请使用 `/monit/rule/move`。\n- `account_id`、`creator_*`、`updater_*`、`created_at`、`updated_at` 由服务端维护,传入将被忽略。\n- `name` 在 `folder_id` 内必须唯一;重名会返回 `InvalidParameter`。\n- 请求体容忍额外的未知字段(向前兼容),未知字段会被忽略。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**(`monit`) |\n\n## 使用说明\n\n- `id` 必填且对应规则必须已存在,否则返回 `InvalidParameter`。\n- 本接口为全量字段替换语义:除下列例外外,未传入的字段按零值保存(随后按默认规则归一,例如 `repeat_interval` 变为 3600),建议先调用 `/monit/rule/v2/info` 获取完整配置后再修改。\n- `enabled` 必须显式传入(包括 `false`),缺失时返回 `InvalidParameter`;更新为 `false` 时服务端会清理该规则的活跃告警。\n- `investigation_targets` 为例外:省略时保留原配置,传 `[]` 清空,传值则整体替换。\n- `folder_id` 不可通过本接口修改,调整文件夹请使用 `/monit/rule/move`。\n- 调用者须对规则所在文件夹有管理权限(账户所有者或管理员、该文件夹或其上级文件夹的创建者,或绑定到该文件夹或其上级文件夹的团队成员),否则返回 `AccessDenied`。\n- `name` 在规则所在文件夹内必须唯一;重名会返回 `InvalidParameter`。\n- `enabled` 为 `true` 时,`ds_type` 必须是支持告警的数据源类型,且 `ds_ids` 中的每个 ID 都必须是已启用并开启告警的数据源,否则返回 `InvalidParameter`。\n- 账户所有者和管理员以外的调用者,须对 `ds_ids` 中列出的、以及 `ds_list` 当前匹配到的每个数据源具备只读权限,否则返回 `AccessDenied`(`no permission to reference datasource \"\"`)。\n- 账户规则数已超出告警规则 License 上限时,调用返回 `AccessDenied`。\n- 处理期间规则被其他请求修改时,返回 HTTP 409(`UndonedOrderExist`,`alert rule was modified; reload and retry`),请重新获取规则后重试。\n- `account_id`、`creator_*`、`updater_*`、`created_at`、`updated_at` 由服务端维护,传入将被忽略。\n- 请求体不得超过 1 MiB,超出时返回 HTTP 413(`EntityTooLarge`)。请求体中额外的未知字段会被忽略(向前兼容)。\n- 每次调用都会记录到账户审计日志,请不要把敏感信息放在请求字段中。", "href": "/zh/api-reference/monitors/alert-rules/monit-rule-write-update-v2", "metadata": { "sidebarTitle": "更新告警规则 V2" @@ -1671,6 +1794,7 @@ "enabled": true, "debug_log_enabled": false, "rule_configs": { + "relate_queries": [], "queries": [ { "name": "A", @@ -1731,6 +1855,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1785,12 +1912,12 @@ "post": { "operationId": "monit-read-query-data", "summary": "查询结构化数据", - "description": "对已配置的数据源执行同步即席查询,并返回稳定的 `query_result.v1` 结果;结果会按自然语义呈现为 frames、records 或 samples。此公开接口要求 monit-edge v0.65.0 或更高版本。", + "description": "对数据源执行同步即席查询,返回 `query_result.v1` 结果,形态为 frames、records 或 samples。", "tags": [ "Monitors/诊断分析" ], "x-mint": { - "content": "## 调用限制\n\n| 项 | 值 |\n| ------ | ----- |\n| 速率限制 | 每账户 **100 次/分钟**、**5 次/秒** |\n| 权限 | 任意有效的 `app_key`(只读,不受特定权限分类限制) |\n| Edge 版本要求 | 受支持的部署要求 **monit-edge v0.65.0 或更高版本** |\n\n## 使用说明\n\n- 此公开接口以 **monit-edge v0.65.0** 为最低受支持版本。迁移期间,WebAPI 仍保留旧版 Edge 适配器:query.v2 结果仍可能保留 frames、records 或 samples,而 legacy rows 只能提供其已保留的信息。这些适配器不会改变最低支持版本;旧协议缺少 query.v3 的取消和错误生命周期语义,legacy rows 已丢失的数据也无法恢复。\n- 公开响应格式固定为 `query_result.v1`,与 Edge 内部查询协议版本无关。必须根据 `result.kind`(`frames`、`records` 或 `samples`)分发结果,不要根据 `ds_type` 或 Edge 版本猜测结果形态。\n- `frames` 结果可以包含多个表格或时序 Frame。字段值按列组织,同一 Frame 中所有字段的值数量一致。\n- `records` 结果可以包含嵌套 JSON 和 null record。超出 JavaScript 安全整数范围的整数字面量会以十进制字符串返回。\n- `samples` 结果包含标签集合和瞬时值。值可以是数字,也可以是字符串 `NaN`、`+Inf` 或 `-Inf`。\n- 最终成功响应上限为 8 MiB,查询结果上限为 1,000 行。超限时请缩短时间范围、减少字段或在数据源侧聚合。\n- 查询失败使用非 2xx HTTP 状态码和标准错误 envelope。不要透明回退到已弃用的 `/monit/query/rows` 接口。\n- WebAPI 跨实例转发和 Edge 执行合计可能耗时 35 秒。客户端超时建议至少设为 40 秒,并在调用方放弃查询时向下传播取消信号。", + "content": "## 调用限制\n\n| 项 | 值 |\n| ------ | ----- |\n| 速率限制 | 每账户 **100 次/分钟**、**5 次/秒** |\n| 权限 | 任意有效的 `app_key`(只读,不受特定权限分类限制) |\n| Edge 版本要求 | 受支持的部署要求 **monit-edge v0.65.0 或更高版本** |\n\n## 使用说明\n\n- 数据源由 `ds_type` 加 `ds_name` 指定,而不是数据源 ID。数据源必须属于当前账户且已启用。若数据源限制了可查询的团队,只有这些团队的成员、其管理团队以及账户所有者或管理员可以查询,其他人会收到 `AccessDenied`。\n- 此公开接口以 **monit-edge v0.65.0** 为最低受支持版本。迁移期间,WebAPI 仍保留旧版 Edge 适配器:query.v2 结果仍可能保留 frames、records 或 samples,而 legacy rows 只能提供其已保留的信息。这些适配器不会改变最低支持版本;旧协议缺少 query.v3 的取消和错误生命周期语义,legacy rows 已丢失的数据也无法恢复。\n- 公开响应格式固定为 `query_result.v1`,与 Edge 内部查询协议版本无关。必须根据 `result.kind`(`frames`、`records` 或 `samples`)分发结果,不要根据 `ds_type` 或 Edge 版本猜测结果形态。\n- `frames` 结果可以包含多个表格或时序 Frame。字段值按列组织,同一 Frame 中所有字段的值数量一致。\n- `records` 结果可以包含嵌套 JSON 和 null record。超出 JavaScript 安全整数范围的整数字面量会以十进制字符串返回。\n- `samples` 结果包含标签集合和瞬时值。值可以是数字,也可以是字符串 `NaN`、`+Inf` 或 `-Inf`。\n- Prometheus 表达式在下发查询前会做语法检查,表达式非法时返回 HTTP 400。\n- 请求体上限为 256 KiB,完整成功响应上限为 10 MiB,超限均返回 HTTP 413。结果超过 1,000 行时返回 HTTP 400。请缩短时间范围、减少字段或在数据源侧聚合。\n- 查询失败使用非 2xx HTTP 状态码和标准错误 envelope。\n- WebAPI 跨实例转发和 Edge 执行合计可能耗时 35 秒。客户端超时建议至少设为 40 秒,并在调用方放弃查询时向下传播取消信号。", "href": "/zh/api-reference/monitors/diagnostics/monit-read-query-data", "metadata": { "sidebarTitle": "查询结构化数据" @@ -1987,7 +2114,7 @@ { "labels": { "__name__": "up", - "instance": "10.101.214.50:7070" + "instance": "203.0.113.10:9090" }, "value": 1 } @@ -2111,7 +2238,7 @@ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **2,000 次/分钟**;**32 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n通过 `/monit/datasource/list` 获取数据源 ID。停用数据源返回 `datasource_disabled`,`alerting_enabled=false` 不阻断工具。错误使用非 2xx HTTP 状态和 `error.code`、`error.message`、`error.reason`。`tool_not_supported` 表示选中的执行端未提供该工具,不表示厂商权限不足。禁止自动切换 Edge 或回退旧 diagnose 重试。\n\n## 使用说明\n\n- 本入口共用两类工具:由执行端 Edge 定义的诊断工具(如 `mysql.overview`、`prometheus.metric_trends`)和命名为 `.query` 的查询工具。工具前缀必须与数据源类型一致。\n- 查询工具要求 Edge 集群支持 Explore 查询(协议里程碑 v0.68.0);诊断工具要求 v0.71.0 基础 invoke 协议。不支持的集群返回 `edge_upgrade_required`、`mixed_edge_versions` 或 `edge_version_unknown`;禁止自动回退 `/monit/query/data` 或其他接口。\n- 查询工具的 `params` 遵循 `tool` 字段描述中按数据源列出的专属 Schema。`expr` 和 `execution` 必填。`limit`/`direction` 只约束原始日志条数与检索方向,不代表 SQL 行数或扫描量。未知扩展字段被容忍,但不参与执行也不透传。\n- 查询结果的 `data` 是完整 Explore 结果:`format` 为 `explore_result.v1`,`result.kind` 为 `samples`、`frames` 或 `logs`;日志结果保留 `applied_limit` 和 `has_more`。查询结果不合成 `summary` 或 `truncated`。\n- 请求体上限 128 KiB;两类工具的完整成功响应上限均为 10 MiB;诊断工具超时最多 25 秒。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **2,000 次/分钟**;**32 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n\n通过 `/monit/datasource/list` 获取数据源 ID。停用数据源返回 `datasource_disabled`,`alerting_enabled=false` 不阻断工具。错误使用非 2xx HTTP 状态和 `error.code`、`error.message`、`error.reason`。`tool_not_supported` 表示选中的执行端未提供该工具,不表示厂商权限不足。禁止自动切换 Edge 或回退旧 diagnose 重试。\n\n## 使用说明\n\n- 调用方需要拥有该数据源的查询权限(见数据源的 `readonly_team_ids`),否则返回 403 `access_denied`;其他账户的数据源返回 404 `datasource_not_found`。\n- 诊断工具仅支持数据源类型 `mysql`、`postgres`、`redis_node`、`redis_sentinel`、`mongodb_mongod`、`mongodb_mongos`、`kafka`、`elasticsearch`、`prometheus`、`loki` 和 `victorialogs`;`oracle`、`clickhouse`、`sls`、`tencent_cls` 只支持各自的 `.query` 工具。其他组合返回 `invalid_request`。\n- 本入口共用两类工具:由执行端 Edge 定义的诊断工具(如 `mysql.overview`、`prometheus.metric_trends`)和命名为 `.query` 的查询工具。工具前缀必须与数据源类型一致。\n- 查询工具要求 Edge 集群支持 Explore 查询(协议里程碑 v0.68.0);诊断工具要求 v0.71.0 基础 invoke 协议。不支持的集群返回 `edge_upgrade_required`、`mixed_edge_versions` 或 `edge_version_unknown`;禁止自动回退 `/monit/query/data` 或其他接口。\n- 查询工具的 `params` 遵循 `tool` 字段描述中按数据源列出的专属 Schema。`expr` 和 `execution` 必填。`limit`/`direction` 只约束原始日志条数与检索方向,不代表 SQL 行数或扫描量。未知扩展字段被容忍,但不参与执行也不透传。\n- 查询结果的 `data` 是完整 Explore 结果:`format` 为 `explore_result.v1`,`result.kind` 为 `samples`、`frames` 或 `logs`;日志结果保留 `applied_limit` 和 `has_more`。查询结果不合成 `summary` 或 `truncated`。\n- 请求体上限 128 KiB;两类工具的完整成功响应上限均为 10 MiB;诊断工具超时最多 25 秒。", "href": "/zh/api-reference/monitors/data-sources/monit-datasource-tools-invoke", "metadata": { "sidebarTitle": "调用数据源工具" @@ -2208,7 +2335,7 @@ } }, "400": { - "description": "标准 HTTP 错误;error.reason:invalid_request。", + "description": "标准 HTTP 错误。参数格式错误或超出范围、数据源已禁用、数据源类型不受支持或数据源未绑定 Edge 集群时,`error.reason` 为 `invalid_request`。数据源 ID 不存在时返回错误码 `ResourceNotFound`,且不带 `reason`。", "content": { "application/json": { "schema": { @@ -2221,17 +2348,7 @@ "$ref": "#/components/responses/Unauthorized" }, "403": { - "description": "标准 HTTP 错误;error.reason:access_denied。", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ErrorResponse" - } - } - } - }, - "404": { - "description": "标准 HTTP 错误;error.reason:datasource_not_found。", + "description": "调用方无权查询该数据源。`error.code` 为 `AccessDenied`,不带 `error.reason`。", "content": { "application/json": { "schema": { @@ -2241,7 +2358,7 @@ } }, "413": { - "description": "标准 HTTP 错误;error.reason:source_too_large、result_too_large。", + "description": "标准 HTTP 错误。`error.reason`:`too_many_rows`、`source_too_large` 或 `result_too_large`。请求体超过 256 KiB 时同样返回 413,不带 `reason`。", "content": { "application/json": { "schema": { @@ -2281,7 +2398,7 @@ } }, "503": { - "description": "标准 HTTP 错误;error.reason:no_active_edge、edge_upgrade_required、mixed_edge_versions、edge_unavailable。", + "description": "标准 HTTP 错误。`error.reason`:`no_active_edge`、`edge_version_unknown`、`edge_upgrade_required`、`mixed_edge_versions` 或 `edge_unavailable`。", "content": { "application/json": { "schema": { @@ -2306,7 +2423,7 @@ "Monitors/诊断分析" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **100 次/分钟**;**16 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n| Edge 版本要求 | 受支持的部署要求 **monit-edge v0.68.0 或更高版本** |\n\n## 使用说明\n\n- 需要数据源原生结果形态时使用本接口;`/monit/query/data` 返回稳定的 `query_result.v1` 契约。本接口根据 `data.result.kind`(`frames`、`samples` 或 `logs`)分发结果。\n- `execution.kind` 决定可接受的配套字段:`instant` 只需 `to_ms`,`range` 需要 `from_ms`、`to_ms` 和 `max_data_points`,`window` 需要 `from_ms` 和 `to_ms`。不接受 `step_seconds`,步长由 `max_data_points` 与 `min_step_seconds` 推导。\n- `args` 用于宏替换(例如 Grafana 风格变量),取值均为字符串。\n- `logs` 结果最多返回 1,000 条,并通过 `applied_limit` 与 `has_more` 说明截断情况。时序与采样结果各最多 1,000 条,成功响应整体上限 8 MiB。\n- WebAPI 跨实例转发与 Edge 执行合计可能耗时 35 秒,客户端超时建议至少 40 秒。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **100 次/分钟**;**16 次/秒** |\n| 权限要求 | **数据源查看**(`monit`) |\n| Edge 版本要求 | 受支持的部署要求 **monit-edge v0.68.0 或更高版本** |\n\n## 使用说明\n\n- 需要数据源原生结果形态时使用本接口;`/monit/query/data` 返回稳定的 `query_result.v1` 契约。本接口根据 `data.result.kind`(`frames`、`samples` 或 `logs`)分发结果。\n- 数据源由 `datasource_id` 指定。数据源必须属于当前账户、已启用、已绑定 Edge 集群,且类型为 `prometheus`、`elasticsearch`、`loki`、`clickhouse`、`mysql`、`oracle`、`postgres`、`sls`、`victorialogs` 或 `tencent_cls` 之一。若数据源限制了可查询的团队,只有这些团队的成员、其管理团队以及账户所有者或管理员可以查询。\n- `execution.kind` 决定可接受的配套字段:`instant` 需要 `to_ms`(`from_ms` 可选),`range` 需要 `from_ms`、`to_ms` 和 `max_data_points`,`window` 需要 `from_ms` 和 `to_ms`。同时给出两个时间时,`from_ms` 必须小于 `to_ms`。不接受 `step_seconds`,步长由 `max_data_points` 与 `min_step_seconds` 推导。\n- `args` 为必填(无参数时传 `{}`),用于宏替换(例如 Grafana 风格变量),取值均为字符串。未知或重复的 JSON 键会被拒绝。\n- `logs` 结果最多返回 1,000 条(`sls` 为 100 条),并通过 `applied_limit` 与 `has_more` 说明截断情况。`frames` 结果最多 1,000 个 frame,表格行合计最多 1,000 行,值合计最多 100,000 个;`samples` 结果最多 1,000 条。请求体上限 256 KiB,成功响应整体上限 10 MiB。\n- 失败使用标准错误 envelope。`error.reason` 是稳定的机器可读取值;数据源 ID 不存在时返回 HTTP 400,错误码为 `ResourceNotFound`,且不带 `reason`。\n- WebAPI 跨实例转发与 Edge 执行合计可能耗时 35 秒,客户端超时建议至少 40 秒。", "href": "/zh/api-reference/monitors/diagnostics/monit-read-query-explore", "metadata": { "sidebarTitle": "执行探索查询" @@ -2331,11 +2448,11 @@ { "name": "X-DSID", "in": "header", - "required": true, + "required": false, "schema": { "type": "string" }, - "description": "要查询的数据源 ID,必须是当前账户下 Prometheus 兼容类型的数据源。" + "description": "要查询的数据源 ID,十进制字符串。必须是当前账户下的 Prometheus 类型数据源。省略时由平台自有的 Prometheus 响应,而不是您的数据源。" } ], "responses": { @@ -2358,7 +2475,7 @@ } }, "400": { - "description": "`X-DSID` 请求头缺失或非法、数据源不存在,或该数据源不是 Prometheus 类型。以 `text/plain` 返回。", + "description": "`X-DSID` 请求头不是数字、数据源不是 Prometheus 类型,或数据源所在集群没有已注册的 monit-edge。以 `text/plain` 返回。", "content": { "text/plain": { "schema": { @@ -2370,18 +2487,14 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, - "500": { - "description": "数据源查询或代理请求失败。以 `text/plain` 返回。", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - } - } + "403": { + "$ref": "#/components/responses/Forbidden" }, - "503": { - "description": "数据源所在集群中没有支持数据源资源代理的 monit-edge。以 `text/plain` 返回,请升级 monit-edge。", + "429": { + "$ref": "#/components/responses/TooManyRequests" + }, + "500": { + "description": "数据源不存在或属于其他账户(消息为 `data source not found`),或数据源查询、代理请求失败。以 `text/plain` 返回。", "content": { "text/plain": { "schema": { @@ -2396,7 +2509,7 @@ "Monitors/告警数据源" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 任意有效的 `app_key`(只读,不受特定权限分类限制) |\n| Edge 版本要求 | 受支持的部署要求 **monit-edge v0.35.0 或更高版本** |\n\n## 使用说明\n\n- 通过 `X-DSID` 请求头指定目标数据源,必须是当前账户下 Prometheus 兼容类型的数据源;可用 `/monit/datasource/list` 获取 ID。\n- 200 响应体是数据源原生的 Prometheus HTTP API 结构,**不是**统一的 `{ request_id, data }` envelope。未到达数据源前发生的失败以 `text/plain` 返回,并携带对应的 4xx/5xx 状态码。\n- 省略 `X-DSID` 时会回退到平台自有的 Prometheus 代理;需要查询指定数据源时必须携带该请求头。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 任意有效的 `app_key`(只读,不受特定权限分类限制) |\n| Edge 版本要求 | 查询指定数据源要求 **monit-edge v0.35.0 或更高版本** |\n\n## 使用说明\n\n- 通过 `X-DSID` 请求头传入目标数据源 ID。数据源必须属于当前账户且为 Prometheus 类型;可用 `/monit/datasource/list` 获取 ID。\n- 200 响应体是数据源原生的 Prometheus HTTP API 结构,**不是**统一的 `{ request_id, data }` envelope。查询字符串参数会原样转发,因此 Prometheus 自身的 `match[]`、`start`、`end` 等参数都可使用。\n- 省略 `X-DSID`,或数据源所在集群中有任意 monit-edge 低于 v0.35.0 时,请求会由平台自有的 Prometheus 响应,而不是您的数据源。请携带该请求头并保持 monit-edge 为较新版本,才能获得数据源自身的取值。\n- 到达数据源之前发生的失败以 `text/plain` 返回,并携带对应的 4xx/5xx 状态码。数据源自身返回的 400 及以上状态码会连同其响应体一并透传。", "href": "/zh/api-reference/monitors/data-sources/monit-prometheus-read-label-values", "metadata": { "sidebarTitle": "查询 Prometheus 标签值列表" @@ -2413,7 +2526,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **300 requests/minute**; **20 requests/second** per account |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- `dashboard_id` 由调用方提供,因此超时后重试会以 `DashboardIDConflict` 失败,而不会创建第二个仪表盘。\n- `definition` 上限 1 MiB,请求体上限 2 MiB。\n- 会记录审计日志。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- `dashboard_id` 由调用方生成(小写的 canonical UUIDv7)。超时后用同一 ID 重试会以 `DashboardIDConflict`(HTTP 409)失败,而不会创建第二个仪表盘。\n- `folder_id` 必须是`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录之一,否则以 `FolderNotFound`(HTTP 404)失败。\n- 新仪表盘的 `revision` 从 1 开始;下次更新、移动或删除时把它作为 `expected_revision` 传入。\n- `definition` 不合法时返回 `InvalidParameter`(HTTP 400),错误信息按 `: <原因>` 逐条列出违规项。定义超过 1 MiB 或超出数量上限(如每个 tab 的 section 数、面板数、查询数或变量数),或请求体超过 2 MiB,返回 `EntityTooLarge`(HTTP 413);`schema_version` 不是 `dashboard.v1` 时返回 `UnsupportedSchemaVersion`(HTTP 422)。\n- 会记录审计日志。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-write-create", "metadata": { "sidebarTitle": "创建仪表盘" @@ -2518,7 +2631,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -2652,7 +2765,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -2691,7 +2804,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | 任意有效 `app_key`;结果限于其所属成员可读的目录 |\n\n## 使用说明\n\n- 位于回收站的仪表盘返回 `DashboardDeleted`,不返回定义。\n- 该读接口除目录可读性外无额外权限点:`app_key` 只能看到其所属成员可读目录下的仪表盘。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 持有有效的 `app_key` 即可调用 |\n\n## 使用说明\n\n- 只能看到位于`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录中的仪表盘;其他仪表盘返回 `DashboardNotFound`(HTTP 404)。\n- 位于回收站的仪表盘返回 `DashboardDeleted`(HTTP 410),不返回定义;可用 `POST /monit/dashboard/trash/list` 找到它,再用 `POST /monit/dashboard/restore` 恢复。\n- 下次更新、移动或删除时,把返回的 `revision` 作为 `expected_revision` 传入。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-read-get", "metadata": { "sidebarTitle": "查看仪表盘详情" @@ -2796,7 +2909,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -2878,7 +2991,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **300 requests/minute**; **20 requests/second** per account |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 发送的是完整定义——这不是部分更新。\n- `expected_revision` 必须等于已存版本号,否则返回 `DashboardRevisionConflict`。\n- 定义逐字节相同时 `changed` 为 false,且不会产生新版本。\n- 仅当调用过程中调用方失去该目录的读权限时,响应中的 `resource` 才为 null。\n- 会记录审计日志。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 需要发送完整定义;未包含的内容会被删除,不会沿用已存版本。\n- `expected_revision` 必须等于已存版本号,否则以 `DashboardRevisionConflict`(HTTP 409)失败;请重新读取仪表盘后重试。\n- 成功后 `revision` 加 1,并记录一条带 `message` 的版本。规范化后的定义与 `schema_version` 都与已存内容相同时,`changed` 为 false,`revision` 不变,也不会记录版本。\n- 标题与描述会去除首尾空白,未填写的数值 `unit` 会存为 `unitless`,因此返回的 `definition` 可能与请求略有不同。\n- 位于回收站的仪表盘返回 `DashboardDeleted`(HTTP 410);调用方无权访问其所在目录时返回 `AccessDenied`。校验与大小错误与 `POST /monit/dashboard/create` 相同。\n- 会记录审计日志。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-write-update", "metadata": { "sidebarTitle": "更新仪表盘" @@ -2985,7 +3098,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3120,7 +3233,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3160,7 +3273,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **300 requests/minute**; **20 requests/second** per account |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 源目录与目标目录都必须可写。\n- 定义不变,因此仅当仪表盘已在 `folder_id` 中时 `changed` 才为 false。\n- 会记录审计日志。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 调用方必须同时能访问当前目录与目标目录(本人创建或归属其团队的目录及其子目录;账户所有者与管理员可访问全部目录)。无权访问当前目录返回 `AccessDenied`;目标目录不存在或无权访问返回 `FolderNotFound`(HTTP 404)。\n- 定义不会改动,但真正移动时 `revision` 仍会加 1 并记录一条版本。若仪表盘已在 `folder_id` 中,`changed` 为 false,且不做任何写入。\n- `expected_revision` 必须等于已存版本号,否则返回 `DashboardRevisionConflict`(HTTP 409);位于回收站的仪表盘返回 `DashboardDeleted`(HTTP 410)。\n- 会记录审计日志。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-write-move", "metadata": { "sidebarTitle": "移动仪表盘" @@ -3267,7 +3380,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3344,12 +3457,12 @@ "post": { "operationId": "monit-dashboard-write-delete", "summary": "删除仪表盘", - "description": "把仪表盘移入回收站。", + "description": "把仪表盘移入回收站,30 天内可恢复。", "tags": [ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **300 requests/minute**; **20 requests/second** per account |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 这是软删除:定义保留 30 天,可用 `POST /monit/dashboard/restore` 恢复。\n- 返回的 `revision` 是本次删除记录的版本号。\n- 会记录审计日志。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 这是软删除:仪表盘进入回收站,删除 30 天后连同全部版本被永久清除。在此之前可用 `POST /monit/dashboard/restore` 恢复。\n- 删除会使 `revision` 加 1;返回的 `revision` 就是恢复时要传入的 `expected_revision`。\n- `expected_revision` 必须等于已存版本号,否则返回 `DashboardRevisionConflict`(HTTP 409);删除已在回收站中的仪表盘返回 `DashboardDeleted`(HTTP 410)。\n- 会记录审计日志。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-write-delete", "metadata": { "sidebarTitle": "删除仪表盘" @@ -3426,7 +3539,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **300 requests/minute**; **20 requests/second** per account |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 省略 `folder_id` 表示恢复到原目录;若原目录已不可写,调用会以 `RestoreFolderRequired` 失败,此时必须指定目标目录。\n- 恢复一个不在回收站中的仪表盘会以 `DashboardNotFound` 失败。\n- 会记录审计日志。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 只能恢复回收站中的仪表盘;其他仪表盘返回 `DashboardNotFound`(HTTP 404)。\n- `expected_revision` 必须等于该仪表盘在回收站中的当前版本号(即删除接口返回、回收站列表中显示的 `revision`),否则返回 `DashboardRevisionConflict`(HTTP 409)。\n- 省略 `folder_id` 表示恢复到原目录。若原目录已不存在,账户所有者与管理员会收到 `RestoreFolderRequired`(HTTP 409),需指定目标目录;其他成员只能恢复原目录仍可访问的仪表盘,否则返回 `DashboardNotFound`。\n- 目标目录不存在或无权访问时返回 `FolderNotFound`(HTTP 404)。恢复会使 `revision` 加 1。\n- 会记录审计日志。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-write-restore", "metadata": { "sidebarTitle": "恢复仪表盘" @@ -3531,7 +3644,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -3607,12 +3720,12 @@ "post": { "operationId": "monit-dashboard-read-list", "summary": "查询仪表盘列表", - "description": "列出某个目录下的仪表盘。", + "description": "列出某个目录下直接存放的仪表盘,支持关键词搜索与分页。", "tags": [ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | 任意有效 `app_key`;结果限于其所属成员可读的目录 |\n\n## 使用说明\n\n- `folder_id` 必填;列表始终包含子目录。\n- `query` 按空白拆分后匹配标题与描述。\n- 此处排序键仅限 `title` 与 `updated_at`,最多两个,默认按 `updated_at` 倒序。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 持有有效的 `app_key` 即可调用 |\n\n## 使用说明\n\n- 只返回直接存放在 `folder_id` 中的仪表盘,不包含其子目录中的仪表盘。跨目录查找请用 `POST /monit/dashboard/search`。\n- `folder_id` 必须是`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录之一,否则以 `FolderNotFound`(HTTP 404)失败。回收站中的仪表盘不会被列出。\n- `query` 按空白拆分为多个词;标题或描述中包含每一个词(子串匹配)的仪表盘才会命中。\n- 排序键为 `title` 与 `updated_at`,最多两个且不可重复;默认按 `updated_at` 倒序,相同值再按 `dashboard_id` 排序。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-read-list", "metadata": { "sidebarTitle": "查询仪表盘列表" @@ -3717,7 +3830,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | 任意有效 `app_key`;结果限于其所属成员可读的目录 |\n\n## 使用说明\n\n- `query` 至少需要一个单词;空查询会以 `InvalidParameter` 失败。\n- 范围限于 `app_key` 所属成员可读的目录——该接口不会扩大访问范围。\n- 排序键仅限 `title` 与 `updated_at`。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 持有有效的 `app_key` 即可调用 |\n\n## 使用说明\n\n- `query` 至少需要一个词;为空或只含空白时以 `InvalidParameter` 失败。标题或描述中包含每一个词(子串匹配)的仪表盘才会命中。\n- 结果只包含`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录中的仪表盘。回收站中的仪表盘不会返回。\n- 排序键为 `title` 与 `updated_at`,最多两个且不可重复;默认按 `updated_at` 倒序。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-read-search", "metadata": { "sidebarTitle": "搜索仪表盘" @@ -3821,7 +3934,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 排序键仅限 `title` 与 `deleted_at`,默认按 `deleted_at` 倒序。\n- 与读接口不同,该接口受「仪表盘管理」权限点管控。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **仪表盘管理**(`monit`) |\n\n## 使用说明\n\n- 列出位于`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录中的已删除仪表盘。每条记录在删除 30 天后被永久清除。\n- 排序键为 `title` 与 `deleted_at`,最多两个且不可重复;默认按 `deleted_at` 倒序。\n- 与其他仪表盘读接口不同,该接口需要「仪表盘管理」权限。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-trash-read-list", "metadata": { "sidebarTitle": "查询回收站仪表盘" @@ -3921,7 +4034,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | 任意有效 `app_key`;结果限于其所属成员可读的目录 |\n\n## 使用说明\n\n- 最多保留 20 个版本(含当前版本);产生新版本时更早的会被丢弃。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 持有有效的 `app_key` 即可调用 |\n\n## 使用说明\n\n- 按最新在前最多返回最近 20 个版本。创建、每次改变定义的更新、移动、删除与恢复都会记录一个版本;更早的版本会被清理。\n- 只有通过 `POST /monit/dashboard/update` 并附带说明写入的版本才有 `message`。\n- 只能看到位于`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录中的仪表盘,其他返回 `DashboardNotFound`(HTTP 404);位于回收站的仪表盘返回 `DashboardDeleted`(HTTP 410)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-revision-read-list", "metadata": { "sidebarTitle": "查询仪表盘版本列表" @@ -4011,7 +4124,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | 任意有效 `app_key`;结果限于其所属成员可读的目录 |\n\n## 使用说明\n\n- 版本号按仪表盘独立编号,从 1 开始。\n- 已滚动出 20 条窗口的版本会返回 `DashboardNotFound`。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 持有有效的 `app_key` 即可调用 |\n\n## 使用说明\n\n- 版本号按仪表盘独立编号,从 1(创建)开始。早于最近 20 个的版本已被清理,返回 `DashboardNotFound`(HTTP 404)。\n- 只能看到位于`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录中的仪表盘;位于回收站的仪表盘返回 `DashboardDeleted`(HTTP 410),需先恢复才能读取历史。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-revision-read-get", "metadata": { "sidebarTitle": "查看仪表盘版本详情" @@ -4112,7 +4225,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -4191,7 +4304,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | 任意有效 `app_key`;结果限于其所属成员可读的目录 |\n\n## 使用说明\n\n- 用于渲染导航,或让 Agent 在执行前定位面板 ID——可避免拉取完整定义。\n- 设置 `target_id` 时只返回包含该 tab/section/panel 的分支;ID 不存在会以 `TargetNotFound` 失败。\n- 面板条目只含可视化 `kind` 与数据源类型,不包含面板查询。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | 无 —— 持有有效的 `app_key` 即可调用 |\n\n## 使用说明\n\n- 可用于渲染导航,或在调用 `POST /monit/dashboard/panel/run` 前定位面板 ID,而无需下载查询。\n- `target_id` 为 tab ID 时返回整个 tab;为 section ID 时返回该 tab,但只含该 section 且不含顶层面板;为面板 ID 时只返回该面板及其所在 tab/section。ID 不存在时以 `TargetNotFound`(HTTP 404)失败。\n- 面板条目只含可视化 `kind` 与数据源类型,不含查询。数据源变量的 `selection` 固定为 `single` 且不含 `all`。\n- 只能看到位于`app_key` 所属成员可访问的目录:其本人创建或归属其所在团队的目录及这些目录的全部子目录;账户所有者与管理员可访问全部目录中的仪表盘;位于回收站的仪表盘返回 `DashboardDeleted`(HTTP 410)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-read-outline", "metadata": { "sidebarTitle": "获取仪表盘大纲" @@ -4334,7 +4447,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **16 requests/second** (no per-minute cap) per account |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 无法解析的变量不会导致调用失败:其条目会带上 `error`,并且不出现在 `selections` 中。\n- 显式传入空的 `values` 表示未解析——解析器不会回退到存储的默认值。\n- 选择最多 20 个变量;变量名需匹配 `^[A-Za-z_][A-Za-z0-9_]{0,63}$`。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **16 次/秒**(无每分钟上限) |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 解析已存仪表盘当前版本的变量。`variables` 是调用方当前的选择;未给出的变量回退到存储的默认值(`custom`、`query` 变量用 `default`;`datasource` 变量用 `default_datasource_id`,若它已不在候选项中,则取按名称排序的第一个候选项)。\n- 无法解析的变量不会导致调用失败:其条目会带上 `error`,并且不出现在 `selections` 中。常见原因:既无选择也无默认值、所选值不在候选项中、依赖项未解析、数据源不可达。\n- 显式传入空的 `values` 表示未解析(`variable_invalid`),解析器不会回退到存储的默认值。\n- 变量按依赖顺序解析,依赖了失败变量的变量也会报错。`variables` 中出现仪表盘未定义的变量名时,调用以 HTTP 400 失败。\n- 每个变量最多返回 1000 个候选项,所有候选项合计须在 8 MiB 以内,否则以 `EntityTooLarge`(HTTP 413)失败。`query` 变量只能对 Prometheus、MySQL、Loki 数据源执行。\n- 调用方须能看到该仪表盘所在的目录,否则返回 `DashboardNotFound`(HTTP 404)。整个调用有 35 秒的总时限,超时返回 `RuntimeTimeout`(HTTP 504)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-variable-read-resolve", "metadata": { "sidebarTitle": "解析仪表盘变量" @@ -4455,7 +4568,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **16 requests/second** (no per-minute cap) per account |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- `context` 为 `new` 时指向尚无仪表盘的目录,为 `existing` 时指向已存仪表盘;两者字段混用会校验失败。\n- 不落库,因此响应中没有 `dashboard_id` 或 `revision`。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **16 次/秒**(无每分钟上限) |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 解析尚未存入仪表盘的草稿变量列表,便于编辑器在保存前测试变量。不落库,因此响应中没有 `dashboard_id` 或 `revision`。\n- 草稿属于已存仪表盘时,`context.kind` 为 `existing` 并带 `dashboard_id`;仪表盘尚不存在时为 `new` 并带 `folder_id`;混用另一种类型的字段会校验失败(HTTP 400)。调用方需要能访问该仪表盘所在目录或该目录(否则返回 403/404)。\n- 草稿 `variables` 按与已存定义相同的规则校验(名称、依赖、选项上限、最多 20 个变量、1 MiB);违规时以 HTTP 400 失败,超出大小限制时为 HTTP 413。\n- 解析行为与「解析仪表盘变量」一致:失败的变量带 `error` 且不出现在 `selections` 中,空的 `values` 选择视为未解析。\n- 整个调用有 35 秒的总时限,超时返回 `RuntimeTimeout`(HTTP 504)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-variable-read-preview", "metadata": { "sidebarTitle": "预览草稿变量" @@ -4604,7 +4717,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **16 requests/second** (no per-minute cap) per account |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 用于在真正执行前展示面板将命中哪个数据源、使用什么表达式。\n- `panel_ids` 接受 1~100 个唯一 ID;面板在仪表盘中不存在时产生 `state: \"error\"` 条目,而不会使整个调用失败。\n- 只有部分查询解析成功的面板返回 `state: \"partial\"`。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **16 次/秒**(无每分钟上限) |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 用于在运行之前展示面板将命中哪个数据源、使用什么表达式。不会执行任何查询。\n- `panel_ids` 接受 1~100 个唯一 ID,按请求顺序返回。面板不在该仪表盘中时,返回 `state: \"error\"`、原因 `panel_missing`,而不会使整个调用失败;文本面板返回 `state: \"error\"`、原因 `invalid_request`。\n- 面板的全部查询解析成功时 `state` 为 `success`,只有部分成功为 `partial`,全部失败为 `error`。`queries` 列出解析成功的查询;`error` 只报告第一个失败。\n- 内置时间变量(如步长、时间范围)根据 `time` 和 `max_data_points` 渲染;`preserve_builtin_variables` 为 `true` 时原样保留,供调用方用自己的窗口渲染。用户变量始终会被解析。\n- 面板查询只能绑定到 Prometheus、MySQL、Loki 数据源。整个调用有 35 秒的总时限,超时返回 `RuntimeTimeout`(HTTP 504)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-query-read-resolve", "metadata": { "sidebarTitle": "解析面板查询" @@ -4730,7 +4843,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **16 requests/second** (no per-minute cap) per account |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 省略 `revision` 表示按当前版本运行;传入它可让调用返回过期错误,而不是返回已被覆盖的数据。\n- `run_state` 汇总各查询状态——部分 ref 成功为 `partial`;数据源接受了调用但查询不匹配其类型时为 `incompatible`。\n- 每个 ref 的 `execution` 载荷随数据源而异且原样透传;`child_request_id` 可用于追踪底层数据源调用。\n- `max_data_points` 默认 100,取值 2~5000。整个响应上限 8 MiB。\n- 单个面板内查询的并发上限为 6。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **32 次/秒**(无每分钟上限) |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 对已存仪表盘当前版本的单个面板,把其全部查询发往对应数据源执行。即使所有查询都失败,调用仍返回 HTTP 200,请查看 `run_state` 以及各 ref 的 `state`、`error`。\n- 省略 `revision`(或传 0)表示按当前版本运行。传入它时,若仪表盘已被修改,调用以 `DashboardRevisionConflict`(HTTP 409)失败,而不是返回基于过期定义的数据。\n- `run_state` 汇总各 ref:全部成功为 `success`,至少一个成功且至少一个未成功为 `partial`,否则为 `cancelled`、`incompatible` 或 `error`。查询已执行但结果与面板可视化不匹配(例如配置的值字段缺失或不是数值)时,该 ref 为 `incompatible`。\n- 每个 ref 的 `execution` 随数据源而异且原样透传;`child_request_id` 标识底层数据源调用。文本面板不能运行(HTTP 400),`panel_id` 不存在时返回 `TargetNotFound`(HTTP 404)。\n- `max_data_points` 默认 100,取值 2~5000。单个面板内最多同时运行 6 个查询。响应超过 8 MiB 时以 `EntityTooLarge`(HTTP 413)拒绝,而不会截断。整个调用有 35 秒的总时限,超时返回 `RuntimeTimeout`(HTTP 504)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-panel-read-run", "metadata": { "sidebarTitle": "运行仪表盘面板" @@ -4891,7 +5004,7 @@ "Monitors/仪表盘" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **16 requests/second** (no per-minute cap) per account |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 用于在用户仍在编辑时校验面板——不会写入任何内容,也不会产生版本。\n- 草稿同样受已存仪表盘的全部限制:网格重叠、各可视化类型的查询数量,以及 1 MiB 定义上限。\n- 响应结构与面板运行一致,只是不含 `dashboard_id`。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **32 次/秒**(无每分钟上限) |\n| 权限要求 | **数据源查看**(`monit`) |\n\n## 使用说明\n\n- 用于在用户仍在编辑面板时检查它:草稿面板及其变量被内联执行,不会写入任何内容,也不会产生版本。\n- `context` 把草稿关联到已存仪表盘(`existing` 并带 `dashboard_id`)或尚无仪表盘的目录(`new` 并带 `folder_id`)。调用方需要能访问该仪表盘所在目录或该目录。\n- 草稿 `panel` 与 `variables` 按与已存定义相同的规则校验(网格、各可视化类型的查询数量、变量引用),且不得超过 1 MiB;违规时以 HTTP 400 失败,超出大小限制时为 HTTP 413。文本面板不能预览。\n- 响应结构与面板运行一致,只是不含 `dashboard_id` 和 `revision`。即使所有查询都失败,也返回 HTTP 200,请查看 `run_state` 以及各 ref 的 `state`、`error`。\n- `max_data_points` 默认 100,取值 2~5000。同时最多运行 6 个查询。响应超过 8 MiB 时以 `EntityTooLarge`(HTTP 413)拒绝。整个调用有 35 秒的总时限,超时返回 `RuntimeTimeout`(HTTP 504)。", "href": "/zh/api-reference/monitors/dashboards/monit-dashboard-panel-read-preview", "metadata": { "sidebarTitle": "预览草稿面板" @@ -5043,7 +5156,7 @@ "legend_alias": "{{env}} requests", "query": { "mode": "range", - "expr": "sum(rate(http_requests_total{env=\"{{env}}\"}[5m]))", + "expr": "sum(rate(http_requests_total{env=\"${env}\"}[5m]))", "args": {}, "min_step_seconds": 30 } @@ -5110,16 +5223,16 @@ "/monit/folder/list": { "post": { "operationId": "monit-folder-read-list", - "summary": "查询监控节点列表", + "summary": "查询监控目录列表", "description": "列出调用方可读的全部监控节点。", "tags": [ "Monitors/规则分组" ], "x-mint": { - "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | **1,000 requests/minute**; **50 requests/second** per account |\n| 权限要求 | **告警规则查看** 或 **节点权限查看**(`monit`) |\n\n## 使用说明\n\n- 响应是可读目录的扁平列表而非树:请用 `parent_id` 与 `parent_path` 重建层级,并在客户端自行搜索。\n- 仪表盘与告警规则共用这棵目录树,因此同一批 ID 会作为仪表盘载荷中的 `folder_id` 出现。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **1,000 次/分钟**;**50 次/秒** |\n| 权限要求 | **告警规则查看**、**告警规则管理**、**节点权限查看**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 响应是可见文件夹的扁平列表而非树:请用 `parent_id` 与 `parent_path` 重建层级,并在客户端自行搜索。账户下没有可见文件夹时返回 `[]`。\n- 账户所有者和管理员可看到全部文件夹。其他成员可看到自己创建的文件夹、归属于自己所在团队的文件夹、这些文件夹下的全部子文件夹,以及到达它们所需经过的祖先文件夹。\n- 仪表盘与告警规则共用这棵文件夹树,因此同一批 ID 会作为仪表盘载荷和告警规则中的 `folder_id` 出现。", "href": "/zh/api-reference/monitors/rule-folders/monit-folder-read-list", "metadata": { - "sidebarTitle": "查询监控节点列表" + "sidebarTitle": "查询监控目录列表" } }, "responses": { @@ -5174,6 +5287,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5187,12 +5303,12 @@ "post": { "operationId": "monit-folder-read-health", "summary": "获取监控目录健康摘要", - "description": "获取可见目录的健康摘要,包含后代目录中的问题。", + "description": "获取可见监控文件夹的问题标记,包含后代文件夹中的问题。", "tags": [ "Monitors/规则分组" ], "x-mint": { - "content": "## 限制\n\n| 项目 | 值 |\n| ------ | ----- |\n| 频率限制 | 每账户 **30 次/分钟**;**2 次/秒** |\n| 权限 | **告警规则查看**、**告警规则管理**、**节点权限查看**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 问题包括活跃告警和告警规则运行问题,并向可见祖先目录汇总。\n- 此操作扫描目录规则和运行状态,请避免频繁轮询。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **30 次/分钟**;**2 次/秒** |\n| 权限要求 | **告警规则查看**、**告警规则管理**、**节点权限查看**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- `items` 对调用方可见的每个文件夹返回一项(与 `/monit/folder/list` 的范围相同),按 `id` 升序排列。\n- 当文件夹自身或其任一后代文件夹中的规则存在活跃告警或运行问题时,`has_issue` 为 true,且该问题也会显示在每一级可见的祖先文件夹上。只统计调用方可读文件夹中的规则。\n- 此操作会扫描文件夹中的规则和运行状态,请避免频繁轮询。", "href": "/zh/api-reference/monitors/rule-folders/monit-folder-read-health", "metadata": { "sidebarTitle": "获取监控目录健康摘要" @@ -5238,6 +5354,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5251,12 +5370,12 @@ "post": { "operationId": "monit-folder-write-create", "summary": "创建监控目录", - "description": "在顶层或有权访问的父目录下创建监控目录。", + "description": "在根级别或调用方有权修改的父文件夹下创建监控文件夹。", "tags": [ "Monitors/规则分组" ], "x-mint": { - "content": "## 限制\n\n| 项目 | 值 |\n| ------ | ----- |\n| 频率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 传入 `parent_id: 0` 或省略该字段以创建顶层目录。您必须有权访问父目录。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 传入 `parent_id: 0` 或省略该字段以创建根文件夹。要在某个父文件夹下创建,调用方必须有权修改它:账户所有者或管理员、该父文件夹或其任一祖先的创建者,或者被分配到该父文件夹或其任一祖先的团队成员。父文件夹不存在时返回 `InvalidParameter`,无权修改父文件夹时返回 `AccessDenied`。\n- 响应为新创建的文件夹。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", "href": "/zh/api-reference/monitors/rule-folders/monit-folder-write-create", "metadata": { "sidebarTitle": "创建监控目录" @@ -5309,6 +5428,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5338,12 +5460,12 @@ "post": { "operationId": "monit-folder-write-update", "summary": "更新监控目录", - "description": "替换有权访问的监控目录的名称、备注和团队归属。", + "description": "替换调用方有权修改的监控文件夹的名称、备注和团队归属。", "tags": [ "Monitors/规则分组" ], "x-mint": { - "content": "## 限制\n\n| 项目 | 值 |\n| ------ | ----- |\n| 频率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 必须传入 `id` 和 `name`。此操作替换可编辑字段:省略 `note` 会清空备注,省略 `team_id` 会重置为 0。\n- 请使用移动接口更改父目录。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 必须传入 `id` 和 `name`。此操作替换可编辑字段:省略 `note` 会清空备注,省略 `team_id` 会重置为 0。\n- 调用方必须有权修改该文件夹:账户所有者或管理员、该文件夹的创建者或其任一祖先的创建者,或者被分配到该文件夹或其任一祖先的团队成员。文件夹不存在时返回 `InvalidParameter`,无权修改时返回 `AccessDenied`。\n- 请使用移动接口更改父文件夹。响应为更新后的文件夹。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", "href": "/zh/api-reference/monitors/rule-folders/monit-folder-write-update", "metadata": { "sidebarTitle": "更新监控目录" @@ -5396,6 +5518,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5430,7 +5555,7 @@ "Monitors/规则分组" ], "x-mint": { - "content": "## 限制\n\n| 项目 | 值 |\n| ------ | ----- |\n| 频率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 您必须有权访问源目录和目标目录。\n- 必须传入 `dest_parent_id`;移至顶层时显式传 0。不能移至自身或后代目录下。\n- 后代目录路径在同一事务中更新。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 调用方必须有权修改源文件夹;除非 `dest_parent_id` 为 0,还必须有权修改目标文件夹。\n- 必须传入 `dest_parent_id`;移至根级别时显式传 0。它不能等于 `id`,不能移至自身或后代文件夹下,否则返回 `InvalidParameter`。移动到当前父文件夹时请求成功,但不产生任何变化。\n- 后代文件夹的路径在同一事务中更新,该文件夹及其全部后代的最后更新人都会记为调用方。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", "href": "/zh/api-reference/monitors/rule-folders/monit-folder-write-move", "metadata": { "sidebarTitle": "移动监控目录" @@ -5470,6 +5595,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5497,12 +5625,12 @@ "post": { "operationId": "monit-folder-write-delete", "summary": "删除监控目录", - "description": "移除子目录、规则和仪表盘后,删除有权访问的监控目录。", + "description": "删除调用方有权修改的空监控文件夹。", "tags": [ "Monitors/规则分组" ], "x-mint": { - "content": "## 限制\n\n| 项目 | 值 |\n| ------ | ----- |\n| 频率限制 | 每账户 **300 次/分钟**;**20 次/秒** |\n| 权限 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 只能删除空目录。存在子目录、告警规则或仪表盘时,返回 HTTP 409,错误码为 `FolderNotEmpty`。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", + "content": "## 限制说明\n\n| 项目 | 说明 |\n| ---- | ---- |\n| 速率限制 | 每个账户 **300 次/分钟**;**20 次/秒** |\n| 权限要求 | **告警规则管理**或**节点权限管理**(`monit`) |\n\n## 使用说明\n\n- 只能删除空文件夹,不会替您删除其中的内容。存在子文件夹、告警规则或仪表盘时,返回 HTTP 409,错误码为 `FolderNotEmpty`。\n- 调用方必须有权修改该文件夹。文件夹不存在时返回 `InvalidParameter`,无权修改时返回 `AccessDenied`。\n- 每次调用均记录账户审计日志。请勿在请求字段中传入密钥。", "href": "/zh/api-reference/monitors/rule-folders/monit-folder-write-delete", "metadata": { "sidebarTitle": "删除监控目录" @@ -5542,6 +5670,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5619,7 +5750,7 @@ "type": "apiKey", "in": "query", "name": "app_key", - "description": "在 Flashduty 控制台 账户 → APP Key 中签发的 app_key。调用任何公开 API 时都必须携带。它等同于所属账户的身份凭证,请妥善保管。" + "description": "在 Flashduty 控制台 我的 → APP Key 中创建的 APP Key。可通过 query 参数 `app_key` 或请求头 `Fd-App-Key` 传入。实际可访问范围是该 APP Key 的权限范围与创建者当前角色权限的交集,请妥善保管。" } }, "responses": { @@ -5666,7 +5797,7 @@ } }, "Forbidden": { - "description": "app_key 有效但没有执行该操作的权限。", + "description": "app_key 有效,但其权限范围或创建者角色不允许该操作或该对象。", "content": { "application/json": { "schema": { @@ -5708,7 +5839,7 @@ } }, "TooManyRequests": { - "description": "命中限流。可能是全局 API 限流、账户级限流或集成级限流。限流按账户聚合。", + "description": "触发频率限制(账户级限制或该接口的平台级上限)。请等待响应头 `Flashcat-Request-Rate-Limit-Delay` 给出的秒数后重试。", "content": { "application/json": { "schema": { @@ -5726,6 +5857,15 @@ } } } + }, + "headers": { + "Flashcat-Request-Rate-Limit-Delay": { + "description": "距当前限流窗口重置的秒数。请求被网关全局保护限流拒绝时不返回该响应头。", + "schema": { + "type": "integer", + "minimum": 0 + } + } } }, "ServerError": { @@ -5998,7 +6138,7 @@ }, "content": { "type": "string", - "description": "审计时刻规则完整配置的 JSON 字符串,仅在 `/monit/rule/audit/detail` 返回,列表接口中省略。" + "description": "变更完成后规则完整配置的 JSON 字符串,仅在 `/monit/rule/audit/detail` 返回,列表接口中省略。由 `/monit/rule/v2/create` 和 `/monit/rule/v2/update` 写入的记录采用 `AlertRuleV2` 结构;由 `/monit/rule/update/fields` 和 `/monit/rule/move` 写入的记录采用规则的存储结构,其检查器配置使用旧版恢复设置,而不是 `recovery_mode` / `end_mode`。" }, "creator_id": { "type": "integer", @@ -6018,7 +6158,7 @@ }, "AlertRuleBasic": { "type": "object", - "description": "列表视图用的告警规则基础信息。", + "description": "列表视图用的告警规则基础信息。`include_descendants` 为 `true` 的列表中只填充 `id`、`folder_id`、`name`,其余字段为零值。", "required": [ "id", "account_id", @@ -6049,27 +6189,30 @@ "account_id": { "type": "integer", "format": "uint64", - "description": "账户 ID。" + "description": "规则所属账户 ID;在 `include_descendants` 为 `true` 的列表中为 `0`。" }, "folder_id": { "type": "integer", "format": "uint64", - "description": "文件夹 ID。" + "description": "直接包含该规则的文件夹 ID;在 `include_descendants` 为 `true` 的列表中可能是所请求文件夹的子孙文件夹。" }, "name": { "type": "string", - "description": "规则名称。" + "description": "规则名称,在所属文件夹内唯一(最长 128 个字符)。" }, "labels": { - "type": "object", + "type": [ + "object", + "null" + ], "additionalProperties": { "type": "string" }, - "description": "自定义标签。" + "description": "规则附加到其告警事件上的自定义标签;在 `include_descendants` 为 `true` 的列表中为 `null`。" }, "ds_type": { "type": "string", - "description": "数据源类型,如 `prometheus`。" + "description": "规则查询的数据源类型。支持告警的类型:`prometheus`、`elasticsearch`、`loki`、`clickhouse`、`mysql`、`oracle`、`postgres`、`sls`、`tencent_cls`、`victorialogs`。只有启用的规则会按此列表校验,因此禁用的规则可能是其他值;在 `include_descendants` 为 `true` 的列表中为空。" }, "enabled": { "type": "boolean", @@ -6077,7 +6220,7 @@ }, "debug_log_enabled": { "type": "boolean", - "description": "是否启用调试日志。" + "description": "是否开启调试日志;为 `true` 时 edge 会为该规则输出详细的评估日志。" }, "cron_pattern": { "type": "string", @@ -6090,7 +6233,7 @@ }, "delay_seconds": { "type": "integer", - "description": "评估延迟(秒)。" + "description": "评估时查询窗口向前偏移的秒数,用于补偿数据摄入延迟。" }, "creator_id": { "type": "integer", @@ -6375,7 +6518,7 @@ "cloud", "self-managed" ], - "description": "部署类型。`cloud` 使用 Elastic Cloud;`self-managed` 使用自托管集群。" + "description": "部署类型,必填。`cloud` 使用 Elastic Cloud(无需 `address`);`self-managed` 使用自建集群(`address` 必填)。" }, "timeout_mills": { "type": "integer", @@ -6592,31 +6735,40 @@ "description": "与类型相关的数据源配置,仅包含与 `type_ident` 匹配的配置块。", "properties": { "prometheus": { - "$ref": "#/components/schemas/DSPrometheusConfig" + "$ref": "#/components/schemas/DSPrometheusConfig", + "description": "`type_ident` 为 `prometheus` 时的配置。" }, "loki": { - "$ref": "#/components/schemas/DSLokiConfig" + "$ref": "#/components/schemas/DSLokiConfig", + "description": "`type_ident` 为 `loki` 时的配置。" }, "mysql": { - "$ref": "#/components/schemas/DSMySQLConfig" + "$ref": "#/components/schemas/DSMySQLConfig", + "description": "`type_ident` 为 `mysql` 时的配置。" }, "oracle": { - "$ref": "#/components/schemas/DSOracleConfig" + "$ref": "#/components/schemas/DSOracleConfig", + "description": "`type_ident` 为 `oracle` 时的配置。" }, "postgres": { - "$ref": "#/components/schemas/DSPostgresConfig" + "$ref": "#/components/schemas/DSPostgresConfig", + "description": "`type_ident` 为 `postgres` 时的配置。" }, "clickhouse": { - "$ref": "#/components/schemas/DSClickHouseConfig" + "$ref": "#/components/schemas/DSClickHouseConfig", + "description": "`type_ident` 为 `clickhouse` 时的配置。" }, "elasticsearch": { - "$ref": "#/components/schemas/DSElasticSearchConfig" + "$ref": "#/components/schemas/DSElasticSearchConfig", + "description": "`type_ident` 为 `elasticsearch` 时的配置。" }, "sls": { - "$ref": "#/components/schemas/DSSLSConfig" + "$ref": "#/components/schemas/DSSLSConfig", + "description": "`type_ident` 为 `sls` 时的配置。" }, "victorialogs": { - "$ref": "#/components/schemas/DSVictoriaLogsConfig" + "$ref": "#/components/schemas/DSVictoriaLogsConfig", + "description": "`type_ident` 为 `victorialogs` 时的配置。" }, "tencent_cls": { "$ref": "#/components/schemas/DSTencentCLSConfig", @@ -6624,23 +6776,28 @@ }, "kafka": { "$ref": "#/components/schemas/DSKafkaConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "`type_ident` 为 `kafka`(仅诊断)时的配置。" }, "mongodb_mongod": { "$ref": "#/components/schemas/DSMongoDBConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "`type_ident` 为 `mongodb_mongod`(仅诊断)时的配置,字段与 `mongodb_mongos` 相同。" }, "mongodb_mongos": { "$ref": "#/components/schemas/DSMongoDBConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "`type_ident` 为 `mongodb_mongos`(仅诊断)时的配置,字段与 `mongodb_mongod` 相同。" }, "redis_node": { "$ref": "#/components/schemas/DSRedisNodeConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "`type_ident` 为 `redis_node`(仅诊断)时的配置。" }, "redis_sentinel": { "$ref": "#/components/schemas/DSRedisSentinelConfig", - "x-flashduty-preserve-absence": true + "x-flashduty-preserve-absence": true, + "description": "`type_ident` 为 `redis_sentinel`(仅诊断)时的配置。" } } }, @@ -6708,11 +6865,11 @@ }, "basic_auth_username": { "type": "string", - "description": "Basic 认证用户名。" + "description": "Basic Auth 用户名,`basic_auth_enabled` 为 `true` 时生效。" }, "basic_auth_password": { "type": "string", - "description": "Basic 认证密码。" + "description": "Basic Auth 密码,`basic_auth_enabled` 为 `true` 时生效。创建、更新和详情响应会原样返回。" }, "headers": { "type": "array", @@ -6853,26 +7010,46 @@ "edge_cluster_name", "updated_at", "payload", - "alerting_enabled" + "alerting_enabled", + "manage_team_id", + "readonly_team_ids", + "creator_id" ], "properties": { "id": { "type": "integer", "format": "uint64", - "description": "唯一数据源 ID。" + "description": "数据源唯一 ID。用作更新、删除、详情接口的 `id`,以及工具调用接口的 `datasource_id`。" }, "account_id": { "type": "integer", "format": "uint64", - "description": "账户 ID。" + "description": "数据源所属账户的 ID,恒为调用方所在账户。" }, "type_ident": { "type": "string", - "description": "数据源类型标识。支持:`prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + "enum": [ + "prometheus", + "loki", + "mysql", + "oracle", + "postgres", + "clickhouse", + "elasticsearch", + "sls", + "tencent_cls", + "victorialogs", + "redis_node", + "redis_sentinel", + "mongodb_mongod", + "mongodb_mongos", + "kafka" + ], + "description": "数据源类型。\n\n告警类(可用于告警规则评估):\n- `prometheus`:兼容 Prometheus 的指标数据源。\n- `loki`:Grafana Loki 日志。\n- `mysql`:MySQL。\n- `oracle`:Oracle 数据库。\n- `postgres`:PostgreSQL。\n- `clickhouse`:ClickHouse。\n- `elasticsearch`:Elasticsearch。\n- `sls`:阿里云日志服务(SLS)。\n- `tencent_cls`:腾讯云日志服务(CLS)。\n- `victorialogs`:VictoriaLogs。\n\n仅诊断类(不能用于告警评估,`alerting_enabled` 恒为 `false`):\n- `redis_node`:单个 Redis 节点。\n- `redis_sentinel`:Redis Sentinel。\n- `mongodb_mongod`:MongoDB mongod 实例。\n- `mongodb_mongos`:MongoDB mongos 路由。\n- `kafka`:Kafka 集群。\n\n存放类型专属配置的 `payload` 键与类型同名。" }, "name": { "type": "string", - "description": "数据源显示名称。" + "description": "数据源名称,在账户内唯一(不区分类型)。" }, "enabled": { "type": "boolean", @@ -6880,11 +7057,11 @@ }, "note": { "type": "string", - "description": "可选描述。" + "description": "自由文本备注;未设置时为空字符串。" }, "address": { "type": "string", - "description": "连接地址。Prometheus/Loki/VictoriaLogs 为 HTTP URL;MySQL/Oracle/Postgres/ClickHouse 为 `host:port`;SLS 为不含 http/https 前缀的 endpoint。 Redis/MongoDB 诊断类型使用单个 host:port(IPv6 加方括号),不接受 URI、userinfo 或查询参数。Kafka 使用 1–32 个不重复、逗号分隔的 host:port 引导地址;payload 不含 broker 列表。规范化后最多 4096 个字符。", + "description": "已保存的连接地址(已规范化)。格式取决于 `type_ident`,各类型格式见创建请求中的 `address` 字段。最长 4096 个字符。", "maxLength": 4096 }, "payload": { @@ -6910,6 +7087,41 @@ "alerting_enabled": { "description": "是否允许告警评估。告警同时要求 enabled=true 且类型支持告警。仅诊断类型固定为 false;false 不阻断非告警查询或工具。", "type": "boolean" + }, + "manage_team_id": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "description": "负责团队 ID。该团队成员可以编辑、删除、启停该数据源并查看其完整配置。`null` 表示未指定负责团队:任何拥有“数据源管理”权限的调用方都可管理。创建者、账户所有者和管理员始终可管理。" + }, + "readonly_team_ids": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint64" + }, + "description": "允许查询和引用该数据源的团队 ID 列表(负责团队、创建者、账户所有者和管理员始终可查询)。`null` 或空数组表示账户内所有成员都可查询。" + }, + "creator_id": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "description": "创建该数据源的成员 ID;未记录时为 `null`。创建者始终可管理该数据源。" + }, + "my_perm": { + "type": "string", + "enum": [ + "manage", + "readonly" + ], + "description": "调用方对该数据源的权限级别,仅出现在列表响应中。\n- `manage`:可编辑、删除、启停、查看配置并查询。\n- `readonly`:只能查询和引用,不能修改或查看配置。" } } }, @@ -6919,20 +7131,41 @@ "properties": { "type": { "type": "string", - "description": "数据源类型标识。省略时返回全部类型。支持:`prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + "description": "仅返回该类型的数据源;省略或留空返回所有类型。无法识别的值不匹配任何数据源,返回空数组。\n\n告警类(可用于告警规则评估):\n- `prometheus`:兼容 Prometheus 的指标数据源。\n- `loki`:Grafana Loki 日志。\n- `mysql`:MySQL。\n- `oracle`:Oracle 数据库。\n- `postgres`:PostgreSQL。\n- `clickhouse`:ClickHouse。\n- `elasticsearch`:Elasticsearch。\n- `sls`:阿里云日志服务(SLS)。\n- `tencent_cls`:腾讯云日志服务(CLS)。\n- `victorialogs`:VictoriaLogs。\n\n仅诊断类(不能用于告警评估,`alerting_enabled` 恒为 `false`):\n- `redis_node`:单个 Redis 节点。\n- `redis_sentinel`:Redis Sentinel。\n- `mongodb_mongod`:MongoDB mongod 实例。\n- `mongodb_mongos`:MongoDB mongos 路由。\n- `kafka`:Kafka 集群。", + "enum": [ + "prometheus", + "loki", + "mysql", + "oracle", + "postgres", + "clickhouse", + "elasticsearch", + "sls", + "tencent_cls", + "victorialogs", + "redis_node", + "redis_sentinel", + "mongodb_mongod", + "mongodb_mongos", + "kafka" + ] + }, + "name": { + "type": "string", + "description": "仅返回名称与该值完全相等的数据源(名称在账户内唯一,因此最多一条)。省略或留空表示不按名称过滤。" } } }, "DataSourceListResponse": { "type": "array", - "description": "数据源列表。本接口不读取 payload 列,因此每项的 `payload` 均为 `null`。", + "description": "账户下调用方有权查询的数据源,按名称排序;没有匹配项时为空数组。列表不读取 `payload`,因此每项的 `payload` 均为 `null`;每项另带 `my_perm`。", "items": { "$ref": "#/components/schemas/DataSourceItem" } }, "DataSourceUpsertRequest": { "type": "object", - "description": "创建或更新数据源的请求体。`id` 仅在更新时必填。`address` 除 Elasticsearch `deployment=cloud` 外均为必填。", + "description": "创建或更新数据源的请求体。`id` 仅更新时必填,创建时忽略。更新会用请求中的值整体替换 `type_ident`、`name`、`note`、`address`、`payload` 和 `edge_cluster_name`,因此必须全部重新发送;仅 `enabled`、`alerting_enabled`、`manage_team_id`、`readonly_team_ids` 在省略时保持原值。除 `deployment=cloud` 的 Elasticsearch 外,`address` 对所有类型必填。", "required": [ "type_ident", "name", @@ -6943,32 +7176,49 @@ "id": { "type": "integer", "format": "uint64", - "description": "数据源 ID。更新时必填,创建时省略。" + "description": "数据源 ID。更新时必填(ID 不存在或属于其他账户时返回 `ResourceNotFound`);创建时忽略。" }, "type_ident": { "type": "string", - "description": "数据源类型标识。支持:`prometheus`, `loki`, `mysql`, `oracle`, `postgres`, `clickhouse`, `elasticsearch`, `sls`, `tencent_cls`, `victorialogs`, `redis_node`, `redis_sentinel`, `mongodb_mongod`, `mongodb_mongos`, `kafka`。" + "enum": [ + "prometheus", + "loki", + "mysql", + "oracle", + "postgres", + "clickhouse", + "elasticsearch", + "sls", + "tencent_cls", + "victorialogs", + "redis_node", + "redis_sentinel", + "mongodb_mongod", + "mongodb_mongos", + "kafka" + ], + "description": "数据源类型。\n\n告警类(可用于告警规则评估):\n- `prometheus`:兼容 Prometheus 的指标数据源。\n- `loki`:Grafana Loki 日志。\n- `mysql`:MySQL。\n- `oracle`:Oracle 数据库。\n- `postgres`:PostgreSQL。\n- `clickhouse`:ClickHouse。\n- `elasticsearch`:Elasticsearch。\n- `sls`:阿里云日志服务(SLS)。\n- `tencent_cls`:腾讯云日志服务(CLS)。\n- `victorialogs`:VictoriaLogs。\n\n仅诊断类(不能用于告警评估,`alerting_enabled` 恒为 `false`):\n- `redis_node`:单个 Redis 节点。\n- `redis_sentinel`:Redis Sentinel。\n- `mongodb_mongod`:MongoDB mongod 实例。\n- `mongodb_mongos`:MongoDB mongos 路由。\n- `kafka`:Kafka 集群。\n\n存放类型专属配置的 `payload` 键与类型同名。" }, "name": { "type": "string", - "description": "数据源显示名称,查询与诊断接口中的 `ds_name` 引用的就是这个名称。" + "description": "数据源名称;必填,在账户内唯一(不区分类型),即查询接口中的 `ds_name`。重名时返回 `InvalidParameter`。" }, "note": { "type": "string", - "description": "可选描述。" + "description": "自由文本备注。更新时省略或传空字符串会清空已保存的备注。" }, "address": { "type": "string", - "description": "连接地址。除 `elasticsearch` 的 `deployment: cloud` 部署外均为必填。Prometheus/Loki/VictoriaLogs 为 HTTP URL;MySQL/Oracle/Postgres/ClickHouse 为 `host:port`;SLS 为不含 `http(s)://` 前缀的 endpoint;`tencent_cls` 必须为 `cls.tencentcloudapi.com` 或 `cls.internal.tencentcloudapi.com`(要求 Monitors edge >= v0.66.0)。 Redis/MongoDB 诊断类型使用单个 host:port(IPv6 加方括号),不接受 URI、userinfo 或查询参数。Kafka 使用 1–32 个不重复、逗号分隔的 host:port 引导地址;payload 不含 broker 列表。规范化后最多 4096 个字符。", + "description": "连接地址;除 `deployment: cloud` 的 `elasticsearch` 外,所有类型都必填。规范化后最长 4096 个字符。各类型格式:\n- `prometheus`、`loki`、`victorialogs`:HTTP URL;不以 `http` 开头时自动补 `http://`。\n- `mysql`、`oracle`、`postgres`:`host:port`。\n- `clickhouse`:一个或多个以逗号分隔的 `host:port`,重复地址会被拒绝。\n- `self-managed` 的 `elasticsearch`:一个或多个以逗号分隔的 HTTP(S) URL(缺省协议为 `http://`),各 URL 的查询参数必须一致,重复地址会被拒绝;`cloud` 部署无需填写。\n- `sls`:不带 `http://` 或 `https://` 前缀的 endpoint。\n- `tencent_cls`:只能是 `cls.tencentcloudapi.com` 或 `cls.internal.tencentcloudapi.com`(要求 Monitors edge >= v0.66.0)。\n- `redis_node`、`redis_sentinel`、`mongodb_mongod`、`mongodb_mongos`:单个 `host:port`(IPv6 须加方括号),不能含 URI、用户信息或查询串。\n- `kafka`:1-32 个互不重复、以逗号分隔的 `host:port` 引导地址(payload 中没有 broker 列表)。", "maxLength": 4096 }, "payload": { "$ref": "#/components/schemas/DSPayload", - "description": "类型相关配置块,必须包含与 `type_ident` 匹配的键。 诊断类型的 password 和 Kafka tls_key 在响应中省略,${env:...} 引用除外;更新时省略保留已保存的秘密,显式空字符串清除。其他配置字段保持原有行为。" + "description": "类型专属配置块,必须包含与 `type_ident` 同名的键。更新会整体替换 payload,需要保留的配置(包括非诊断类型的凭据,可通过详情接口读取)都要重新发送。例外:诊断类型省略密码(以及 Kafka 的 `tls_key`)表示保留已保存的值,传空字符串表示清除;`tencent_cls` 省略或传空的 `secret_key` 表示保留已保存的密钥。修改 `type_ident` 时不会沿用已保存的密钥。" }, "edge_cluster_name": { "type": "string", - "description": "负责使用该数据源评估规则的 Monitors Edge 集群名称。" + "description": "负责评估规则和执行查询的 Monitors edge 集群名称,必须是账户下已存在的 edge 集群,否则返回 `InvalidParameter`。更新时修改该值会关闭使用此数据源的规则上的未恢复告警。" }, "enabled": { "type": "boolean", @@ -6979,6 +7229,27 @@ "description": "是否允许数据源用于告警。创建时省略:支持告警的类型默认为 true,仅诊断类型默认为 false;更新时省略保留当前值。null 非法。redis_node、redis_sentinel、mongodb_mongod、mongodb_mongos 和 kafka 不允许 true。有启用规则引用时,关闭用途返回冲突。", "type": "boolean", "x-flashduty-preserve-absence": true + }, + "manage_team_id": { + "type": [ + "integer", + "null" + ], + "format": "uint64", + "description": "负责团队 ID(含义见响应中的同名字段)。创建时省略表示不指定负责团队;更新时省略保持原值,传 `null` 或 `0` 表示清除。`readonly_team_ids` 非空时必须填写。", + "x-flashduty-preserve-absence": true + }, + "readonly_team_ids": { + "type": [ + "array", + "null" + ], + "items": { + "type": "integer", + "format": "uint64" + }, + "description": "允许查询和引用该数据源的团队 ID 列表(含义见响应中的同名字段)。创建时省略表示不限制;更新时省略保持原值,传 `null` 或空数组表示清除(所有人可查询)。重复值和 `0` 会被去掉。依赖 `manage_team_id`:列表非空而未指定负责团队时返回 `InvalidParameter`。", + "x-flashduty-preserve-absence": true } } }, @@ -6991,7 +7262,7 @@ }, "message": { "type": "string", - "description": "用户可读的错误描述,语言会跟随调用方的 Accept-Language。可能包含字段名、ID 等请求上下文。", + "description": "按响应语言(query 参数 `locale` / `lang` 或请求头 `Accept-Language`)返回的错误描述,可能包含出错的字段名,请不要解析它。", "example": "The specified parameter template_id is not valid." }, "reason": { @@ -7007,7 +7278,7 @@ }, "EmptyResponse": { "type": "object", - "description": "空响应体。成功时服务端返回 `data: null`。", + "description": "无返回数据。不同接口的 `data` 可能是 `{}`,也可能不出现在响应中;请只根据 HTTP 200 且没有 `error` 判断成功。", "properties": {} }, "EnabledTime": { @@ -7019,21 +7290,21 @@ "items": { "type": "integer" }, - "description": "星期几,0 = 周日。" + "description": "时间窗口适用的星期,`0` = 周日至 `6` = 周六;不能为空,不能重复。" }, "stime": { "type": "string", - "description": "起始时间,如 `09:00`。" + "description": "开始时间,24 小时制 `HH:MM` 格式,如 `09:00`。" }, "etime": { "type": "string", - "description": "结束时间,如 `18:00`。" + "description": "结束时间,24 小时制 `HH:MM` 格式,如 `18:00`。" } } }, "ErrorCode": { "type": "string", - "description": "Flashduty 错误码枚举。每个失败响应的 `error.code` 都是下列稳定值之一,HTTP 状态码仅作参考。\n\n| 错误码 | HTTP | 含义 |\n|---|---|---|\n| `OK` | 200 | 保留值,正常错误响应不会返回。 |\n| `InvalidParameter` | 400 | 必填参数缺失或未通过校验。 |\n| `BadRequest` | 400 | 通用的 400 错误,通常是请求本身不合法。 |\n| `InvalidContentType` | 400 | 请求头 `Content-Type` 不是 `application/json`。 |\n| `ResourceNotFound` | 400 | 目标资源不存在。注意 HTTP 状态码是 400 而非 404(历史设计)。 |\n| `NoLicense` | 400 | 功能需要有效授权,但未找到可用的 license。 |\n| `ReferenceExist` | 400 | 该资源仍被其他实体引用,无法删除。 |\n| `Unauthorized` | 401 | `app_key` 缺失、无效或已过期。 |\n| `BalanceNotEnough` | 402 | 账户余额不足,无法执行需要计费的操作。 |\n| `AccessDenied` | 403 | 身份认证通过,但 RBAC 权限不足以执行该操作。 |\n| `RouteNotFound` | 404 | 请求的 URL 路径不是已知路由。 |\n| `MethodNotAllowed` | 405 | 当前路径不接受所使用的 HTTP 方法。 |\n| `UndonedOrderExist` | 409 | 账户存在未完成的订单,请稍后重试。 |\n| `RequestLocked` | 423 | 因连续失败被临时锁定。 |\n| `EntityTooLarge` | 413 | 请求体超过允许的最大长度。 |\n| `RequestTooFrequently` | 429 | 命中限流(全局、账户级或集成级)。 |\n| `RequestVerifyRequired` | 428 | 操作需要二次验证码,但未提供。 |\n| `DangerousOperation` | 428 | 危险操作,需要进行 MFA 验证。 |\n| `InternalError` | 500 | 服务端未预期错误。反馈问题请附上 `request_id`。 |\n| `ServiceUnavailable` | 503 | 后端依赖不可用,请稍后重试。 |", + "description": "错误码。所有失败响应都会把 `error.code` 设为下列稳定字符串之一,请以它而不是 HTTP 状态码做判断。\n\n| 错误码 | HTTP | 含义 |\n|---|---|---|\n| `OK` | 200 | 保留值,失败的请求不会返回。 |\n| `InvalidParameter` | 400 | 参数缺失、类型错误或未通过校验,`message` 通常会指出字段名。 |\n| `BadRequest` | 400 | 请求违反业务规则或与对象当前状态冲突,`message` 会说明原因。 |\n| `InvalidContentType` | 400 | 请求体没有以 `application/json` 发送。 |\n| `ResourceNotFound` | 400 | 引用的对象在本账户中不存在或已删除。注意 HTTP 状态码是 400 而不是 404。 |\n| `NoLicense` | 400 | 账户套餐不包含该功能、套餐配额已用完、套餐已过期或额度不足。 |\n| `ReferenceExist` | 400 | 对象仍被其他对象引用,无法删除。 |\n| `Unauthorized` | 401 | APP Key 缺失、无效或已删除。 |\n| `BalanceNotEnough` | 402 | 仅用于控制台计费流程,Open API 接口不会返回。 |\n| `AccessDenied` | 403 | APP Key 的权限范围或创建者角色不允许该操作或该对象。 |\n| `RouteNotFound` | 404 | 没有与该 HTTP 方法和路径匹配的接口。 |\n| `MethodNotAllowed` | 405 | 路径存在,但不支持该 HTTP 方法。 |\n| `UndonedOrderExist` | 409 | 仅用于控制台计费流程,Open API 接口不会返回。 |\n| `EntityTooLarge` | 413 | 请求体超出大小限制。 |\n| `RequestLocked` | 423 | 仅用于控制台登录保护,Open API 接口不会返回。 |\n| `RequestVerifyRequired` | 428 | 仅用于控制台验证码流程,Open API 接口不会返回。 |\n| `DangerousOperation` | 428 | 仅用于控制台高风险操作的 MFA 校验,Open API 接口不会返回。 |\n| `RequestTooFrequently` | 429 | 触发频率限制;请等待响应头 `Flashcat-Request-Rate-Limit-Delay` 给出的秒数后再重试。 |\n| `InternalError` | 500 | 服务端意外错误;请退避后重试,反馈问题时附上 `request_id`。 |\n| `ServiceUnavailable` | 503 | 后端依赖过载或不可用,请退避后重试。 |", "enum": [ "OK", "InvalidParameter", @@ -7048,35 +7319,35 @@ "RouteNotFound", "MethodNotAllowed", "UndonedOrderExist", - "RequestLocked", "EntityTooLarge", - "RequestTooFrequently", + "RequestLocked", "RequestVerifyRequired", "DangerousOperation", + "RequestTooFrequently", "InternalError", "ServiceUnavailable" ], "x-enumDescriptions": { - "OK": "保留值,正常错误响应不会返回。", - "InvalidParameter": "必填参数缺失或未通过校验。", - "BadRequest": "通用的 400 错误,通常是请求本身不合法。", - "InvalidContentType": "请求头 `Content-Type` 不是 `application/json`。", - "ResourceNotFound": "目标资源不存在。注意 HTTP 状态码是 400 而非 404(历史设计)。", - "NoLicense": "功能需要有效授权,但未找到可用的 license。", - "ReferenceExist": "该资源仍被其他实体引用,无法删除。", - "Unauthorized": "`app_key` 缺失、无效或已过期。", - "BalanceNotEnough": "账户余额不足,无法执行需要计费的操作。", - "AccessDenied": "身份认证通过,但 RBAC 权限不足以执行该操作。", - "RouteNotFound": "请求的 URL 路径不是已知路由。", - "MethodNotAllowed": "当前路径不接受所使用的 HTTP 方法。", - "UndonedOrderExist": "账户存在未完成的订单,请稍后重试。", - "RequestLocked": "因连续失败被临时锁定。", - "EntityTooLarge": "请求体超过允许的最大长度。", - "RequestTooFrequently": "命中限流(全局、账户级或集成级)。", - "RequestVerifyRequired": "操作需要二次验证码,但未提供。", - "DangerousOperation": "危险操作,需要进行 MFA 验证。", - "InternalError": "服务端未预期错误。反馈问题请附上 `request_id`。", - "ServiceUnavailable": "后端依赖不可用,请稍后重试。" + "OK": "保留值,失败的请求不会返回。", + "InvalidParameter": "参数缺失、类型错误或未通过校验,`message` 通常会指出字段名。", + "BadRequest": "请求违反业务规则或与对象当前状态冲突,`message` 会说明原因。", + "InvalidContentType": "请求体没有以 `application/json` 发送。", + "ResourceNotFound": "引用的对象在本账户中不存在或已删除。注意 HTTP 状态码是 400 而不是 404。", + "NoLicense": "账户套餐不包含该功能、套餐配额已用完、套餐已过期或额度不足。", + "ReferenceExist": "对象仍被其他对象引用,无法删除。", + "Unauthorized": "APP Key 缺失、无效或已删除。", + "BalanceNotEnough": "仅用于控制台计费流程,Open API 接口不会返回。", + "AccessDenied": "APP Key 的权限范围或创建者角色不允许该操作或该对象。", + "RouteNotFound": "没有与该 HTTP 方法和路径匹配的接口。", + "MethodNotAllowed": "路径存在,但不支持该 HTTP 方法。", + "UndonedOrderExist": "仅用于控制台计费流程,Open API 接口不会返回。", + "EntityTooLarge": "请求体超出大小限制。", + "RequestLocked": "仅用于控制台登录保护,Open API 接口不会返回。", + "RequestVerifyRequired": "仅用于控制台验证码流程,Open API 接口不会返回。", + "DangerousOperation": "仅用于控制台高风险操作的 MFA 校验,Open API 接口不会返回。", + "RequestTooFrequently": "触发频率限制;请等待响应头 `Flashcat-Request-Rate-Limit-Delay` 给出的秒数后再重试。", + "InternalError": "服务端意外错误;请退避后重试,反馈问题时附上 `request_id`。", + "ServiceUnavailable": "后端依赖过载或不可用,请退避后重试。" }, "example": "InvalidParameter" }, @@ -7122,11 +7393,11 @@ "properties": { "name": { "type": "string", - "description": "规则名称。" + "description": "该结果对应的规则名称;规则 ID 不存在时为 `id: `。" }, "message": { "type": "string", - "description": "成功时为空,失败时为错误信息。" + "description": "该规则的处理结果。成功时,`/monit/rule/update/fields` 返回空字符串,`/monit/rule/move` 返回本地化的成功文案(`Move successfully` / `移动成功`);失败时为错误信息。" } } }, @@ -7424,7 +7695,7 @@ "type": "integer", "format": "uint64" }, - "description": "要更新的规则 ID 列表。" + "description": "要更新的规则 ID 列表,至少包含一个 ID。" }, "fields": { "type": "array", @@ -7448,18 +7719,18 @@ "repeat_total" ] }, - "description": "要更新的字段名列表。只有列出的字段会被更新,新值从同名请求字段读取;未列出的字段即使传值也会被忽略。" + "description": "要更新的字段名列表。每个列出的字段取同名请求字段的值,未传值时设为零值;未列出的字段即使传值也会被忽略。出现未知字段名时整个调用返回 `InvalidParameter`。" }, "labels": { "type": "object", "additionalProperties": { "type": "string" }, - "description": "自定义标签键值对,整体替换现有标签。仅当 `fields` 包含 `labels` 时生效。" + "description": "自定义标签键值对,整体替换现有标签。仅当 `fields` 包含 `labels` 时生效;不能与 `labels_patch` 同时传入。" }, "ds_type": { "type": "string", - "description": "数据源类型标识。仅当 `fields` 包含 `ds_type` 时生效。" + "description": "数据源类型标识。启用的规则必须使用支持告警的类型:`prometheus`、`elasticsearch`、`loki`、`clickhouse`、`mysql`、`oracle`、`postgres`、`sls`、`tencent_cls`、`victorialogs`。仅当 `fields` 包含 `ds_type` 时生效。" }, "ds_list": { "type": "array", @@ -7490,7 +7761,7 @@ }, "timezone": { "type": "string", - "description": "告警规则执行时区,IANA 时区名,默认 `Asia/Shanghai`。", + "description": "规则执行时区,取 IANA 时区名(如 `Asia/Shanghai`、`UTC`);为空时按 `Asia/Shanghai` 处理。仅当 `fields` 包含 `timezone` 时生效。", "default": "Asia/Shanghai" }, "delay_seconds": { @@ -7509,11 +7780,11 @@ "additionalProperties": { "type": "string" }, - "description": "附加注解键值对,随告警事件下发;键不允许以 `$` 开头(该前缀保留给查询字段)。仅当 `fields` 包含 `annotations` 时生效。" + "description": "随告警事件下发的注解键值对,整体替换现有注解,键不允许以 `$` 开头(该前缀保留给查询字段)。仅当 `fields` 包含 `annotations` 时生效;不能与 `annotations_patch` 同时传入。" }, "description": { "type": "string", - "description": "规则描述(Markdown)。仅当 `fields` 包含 `description` 时生效。" + "description": "规则描述,按规则现有的 `description_type` 渲染(本接口无法修改该格式)。仅当 `fields` 包含 `description` 时生效。" }, "channel_ids": { "type": "array", @@ -7526,20 +7797,20 @@ "repeat_interval": { "type": "integer", "format": "int64", - "description": "告警通知重复间隔(秒)。仅当 `fields` 包含 `repeat_interval` 时生效。" + "description": "告警通知重复间隔(秒);小于 1 时按 3600 处理,最大 2147483647。仅当 `fields` 包含 `repeat_interval` 时生效。" }, "repeat_total": { "type": "integer", "format": "int64", - "description": "最大重复通知次数。仅当 `fields` 包含 `repeat_total` 时生效。" + "description": "最大重复通知次数;小于 1 时按 3 处理,最大 2147483647。仅当 `fields` 包含 `repeat_total` 时生效。" }, "labels_patch": { "$ref": "#/components/schemas/StringMapPatch", - "description": "标签的增量更新,仅在 `fields` 包含 `labels` 时生效;与 `labels` 同时发送时优先使用本字段。" + "description": "标签的增量更新,未提及的标签保持不变。要求 `fields` 包含 `labels`,且不能与 `labels` 同时传入,否则返回 `InvalidParameter`。" }, "annotations_patch": { "$ref": "#/components/schemas/StringMapPatch", - "description": "注解的增量更新,仅在 `fields` 包含 `annotations` 时生效;与 `annotations` 同时发送时优先使用本字段。" + "description": "注解的增量更新,未提及的注解保持不变。要求 `fields` 包含 `annotations`,且不能与 `annotations` 同时传入,否则返回 `InvalidParameter`。" } } }, @@ -7565,7 +7836,7 @@ "id": { "type": "integer", "format": "uint64", - "description": "审计记录 ID——来自 `POST /monit/rule/audits` 返回行的 `id`,不是规则 ID。传规则 ID 会返回 HTTP 400。" + "description": "审计记录 ID——来自 `POST /monit/rule/audits` 返回行的 `id`,不是规则 ID。传入规则 ID 时会被当作审计记录 ID 查询,通常返回 `InvalidParameter`(`alert rule audit not found`)或一条不相关的记录。" } } }, @@ -7581,7 +7852,7 @@ "type": "integer", "format": "uint64" }, - "description": "规则 ID 列表。" + "description": "要删除的告警规则 ID 列表,至少包含一个 ID,可通过 `POST /monit/rule/list/basic` 获取。" } } }, @@ -7606,15 +7877,15 @@ "folder_id": { "type": "integer", "format": "uint64", - "description": "文件夹 ID,必须是已存在的文件夹;传 `0` 会返回 `folder_not_found` 错误。" + "description": "要列出的文件夹 ID,必须是调用者有管理权限的已存在文件夹;传 `0` 或不存在的 ID 返回 `InvalidParameter`。" }, "include_descendants": { "type": "boolean", - "description": "是否同时包含所有子孙文件夹中的规则。为 `true` 时返回的每项仅包含 `id`、`folder_id`、`name` 三个字段;配合 `query` / `limit` 用于规则选择器场景。" + "description": "是否同时搜索所有子孙文件夹。为 `true` 时结果按名称排序、受 `limit` 限制,且每项只填充 `id`、`folder_id`、`name`(其余字段为零值);可配合 `query` 用于规则选择器场景。" }, "query": { "type": "string", - "description": "规则名模糊过滤,仅在 `include_descendants` 为 `true` 时生效。" + "description": "按规则名称子串过滤;纯数字时还会匹配该 ID 的规则。仅在 `include_descendants` 为 `true` 时生效。" }, "limit": { "type": "integer", @@ -7637,12 +7908,12 @@ "type": "integer", "format": "uint64" }, - "description": "要移动的规则 ID 列表。" + "description": "要移动的规则 ID 列表,至少包含一个 ID。" }, "dest_folder_id": { "type": "integer", "format": "uint64", - "description": "目标文件夹 ID,可通过 `POST /monit/folder/list` 获取。" + "description": "目标文件夹 ID,可通过 `POST /monit/folder/list` 获取。不能为 0;文件夹不存在或调用者对其无管理权限时,整个调用返回 `AccessDenied`。" } } }, @@ -7748,16 +8019,15 @@ "example": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" }, "data": { - "description": "每个接口自己的业务 payload,详见各接口的 200 响应 schema。" + "description": "接口返回的数据,格式见各接口的 200 响应。没有返回数据的接口会返回 `{}` 或完全不带 `data`。" } }, "required": [ - "request_id", - "data" + "request_id" ] }, "QueryDataRequest": { - "description": "稳定结构化查询接口的请求。字段与已下线的 rows 接口一致。", + "description": "结构化查询接口的请求体。", "allOf": [ { "$ref": "#/components/schemas/QueryRowsRequest" @@ -7999,33 +8269,49 @@ "account_id": { "type": "integer", "format": "int64", - "description": "可选的一致性校验。若提供,必须等于已认证账户;不一致将被拒绝。业务执行始终使用已认证账户。" + "description": "可选的一致性校验。若提供,必须等于已认证账户,否则请求以 `AccessDenied` 失败。查询始终以已认证账户执行。" }, "ds_type": { "type": "string", - "description": "数据源类型;必须匹配租户下已配置的数据源。示例:`prometheus`、`loki`、`victorialogs`、`sls`、`elasticsearch`、`mysql`、`postgres`、`oracle`、`clickhouse`。" + "description": "数据源类型,需要与 `ds_name` 一起匹配账户下一个已启用的数据源。\n\n- `prometheus`:Prometheus 兼容数据源,`expr` 为 PromQL。\n- `loki`:Grafana Loki,`expr` 为 LogQL。\n- `victorialogs`:VictoriaLogs。\n- `sls`:阿里云日志服务(SLS)。\n- `tencent_cls`:腾讯云日志服务(CLS),需要 monit-edge v0.66.0 或更高版本。\n- `elasticsearch`:Elasticsearch。\n- `mysql`:MySQL,`expr` 为 SQL。\n- `postgres`:PostgreSQL,`expr` 为 SQL。\n- `oracle`:Oracle 数据库,`expr` 为 SQL。\n- `clickhouse`:ClickHouse,`expr` 为 SQL。\n\n其他数据源类型(例如 MongoDB、Redis、Kafka)会被拒绝。", + "enum": [ + "clickhouse", + "elasticsearch", + "loki", + "mysql", + "oracle", + "postgres", + "prometheus", + "sls", + "tencent_cls", + "victorialogs" + ] }, "ds_name": { "type": "string", - "description": "数据源名称;必须匹配租户下已配置的数据源。" + "description": "数据源名称,可从 `/monit/datasource/list` 获取。数据源必须已启用;账户下不存在该名称的数据源时返回 HTTP 400。" }, "expr": { "type": "string", - "description": "查询表达式。语法取决于 `ds_type`,由对应的 monit-edge 客户端解释(Prometheus 用 PromQL,Loki 用 LogQL,SQL 类数据源用 SQL,等等)。" + "description": "使用 `ds_type` 对应查询语言的表达式(`prometheus` 为 PromQL,`loki` 为 LogQL,SQL 类数据源为 SQL,等等)。必填,最大 64 KiB(`tencent_cls` 为 12 KiB)。此接口不支持 Loki 的 `$__auto`,请使用固定时长,例如 `[5m]`。Prometheus 表达式在下发前会做语法检查。", + "minLength": 1 }, "delay_seconds": { "type": "integer", - "description": "应用于点查询(Prometheus、Loki stats、VictoriaLogs stats)的回看偏移,单位秒。明细 / raw 查询忽略该字段。", - "default": 0 + "description": "回看偏移,单位秒,取值 0 到 86400。应用于点查询(Prometheus、Loki stats、VictoriaLogs stats);明细 / raw 查询忽略该字段。当 `args` 带有绝对时间 `.time` 且 Edge 为 v0.74.0 或更高版本时,以绝对时间为准,不再应用此偏移。", + "default": 0, + "minimum": 0, + "maximum": 86400 }, "args": { "type": "object", - "description": "透传给 monit-edge 的多态键值扩展参数。所有值必须是字符串,键一律按数据源加前缀(如 `sls.project`、`loki.type`)。校验规则取决于 `ds_type`:SLS 必须提供 `sls.project` 与 `sls.logstore`;Elasticsearch 的 `es.type` 只接受 `sql` 或不传,其他值一律拒绝;Loki 与 VictoriaLogs 的 `.type` 接受 `stats`、`raw` 或不传,其中 `raw` 还必须给出时间范围——`.start` + `.end`,或 `.timespan.value` + `.timespan.unit`(单位取 `s`/`m`/`h`/`d`)。Prometheus 及其余 SQL 类数据源完全忽略 `args`。", + "description": "额外的查询参数,字符串键值对;键按数据源加前缀(例如 `sls.project`、`loki.type`)。最多 128 项,键最长 256 字节,值最长 64 KiB,总计不超过 128 KiB。可接受的参数取决于 `ds_type`:\n\n- `prometheus`:可选 `prometheus.time`,评估时间,Unix 秒,不能晚于当前时间。\n- `loki`、`victorialogs`:`.type` 取 `stats`(默认)或 `raw`。`stats` 可带 `.time`(Unix 秒,不能晚于当前时间)。`raw` 必须给出时间范围,可用 `.start` + `.end`(Unix 秒),或 `.timespan.value` + `.timespan.unit`(`s`、`m`、`h` 或 `d`),跨度不超过 6 小时,并可带 `.limit`,取值 1 到 1001。\n- `sls`:必须提供 `sls.project` 和 `sls.logstore`。可选 `sls.lines`(1 到 100)、`sls.offset`(0 或更大),以及不超过 6 小时的时间范围,可用 `sls.from` + `sls.to`(Unix 秒)或 `sls.timespan.value` + `sls.timespan.unit` 给出。\n- `tencent_cls`:必须提供 `tencent_cls.region`、`tencent_cls.topic_id`、`tencent_cls.query_mode`(`raw` 或 `analysis`)和 `tencent_cls.syntax`(`cql` 或 `lucene`)。可选 `tencent_cls.limit`(1 到 100,仅 `raw` 模式,需要 monit-edge v0.67.0 或更高版本),以及时间范围,可用 `tencent_cls.from` + `tencent_cls.to`(Unix 秒)或 `tencent_cls.timespan.value` + `tencent_cls.timespan.unit` 给出,`raw` 模式不超过 6 小时,`analysis` 模式不超过 24 小时。其他任何键都会被拒绝。\n- `elasticsearch`:`es.type` 只能为 `sql` 或不传,其他值会被拒绝。\n- `mysql`、`postgres`、`oracle`、`clickhouse`:未定义任何参数。\n\n绝对时间 `.time` 只对其对应的数据源类型有效。v0.74.0 之前的 Edge 通过回看偏移近似实现,且只接受最近 86,400 秒内的时间。", "additionalProperties": { "type": "string" } } - } + }, + "description": "要执行的查询。`ds_type` 与 `ds_name` 共同选定数据源;`expr` 与 `args` 由该类型的数据源解释。" }, "DSTencentCLSConfig": { "type": "object", @@ -8101,7 +8387,7 @@ }, "StringMapPatch": { "type": "object", - "description": "map 字段的增量更新:`set` 中的键会被插入或覆盖,`delete` 中的键会被删除,其余键保持不变。", + "description": "map 字段的增量更新:`set` 中的键会被插入或覆盖,`delete` 中的键会被删除,其余键保持不变。`set` / `delete` 至少一个非空,键不能为空白,同一个键不能同时出现在两者中,也不能在 `delete` 中重复。", "properties": { "set": { "type": "object", @@ -8123,7 +8409,7 @@ "description": "诊断数据源连接配置。", "properties": { "password": { - "description": "认证密码,支持 ${env:NAME}。更新时省略保留;显式空字符串清除。响应中省略字面密码。", + "description": "认证密码,支持 ${env:NAME}。使用 SASL 认证时须与 `username` 一起提供,`sasl_mechanism` 为 `none` 时必须为空。更新时省略表示保留已保存的密码,显式传空字符串表示清除。响应中不返回明文密码。", "type": "string", "x-flashduty-preserve-absence": true }, @@ -8155,7 +8441,7 @@ }, "tls_enabled": { "default": false, - "description": "是否启用 TLS,默认为 false。", + "description": "是否启用 TLS,默认 false。为 false 时保存时会清空所有 `tls_*` 字段。", "type": "boolean" }, "tls_key": { @@ -8180,7 +8466,7 @@ "type": "boolean" }, "username": { - "description": "认证用户名,支持 ${env:NAME} 引用。", + "description": "认证用户名,支持 ${env:NAME} 引用。`sasl_mechanism` 为 `plain`、`scram-sha-256` 或 `scram-sha-512` 时必填,为 `none` 时必须为空。", "type": "string" } }, @@ -8212,7 +8498,7 @@ }, "tls_enabled": { "default": false, - "description": "是否启用 TLS,默认为 false。", + "description": "是否启用 TLS,默认 false。为 false 时保存时会清空所有 `tls_*` 字段。", "type": "boolean" }, "tls_max_version": { @@ -8232,7 +8518,7 @@ "type": "boolean" }, "username": { - "description": "认证用户名,支持 ${env:NAME} 引用。", + "description": "认证用户名,支持 ${env:NAME} 引用。须与 `password` 一起提供。", "type": "string" } }, @@ -8260,7 +8546,7 @@ "type": "integer" }, "username": { - "description": "认证用户名,支持 ${env:NAME} 引用。", + "description": "认证用户名,支持 ${env:NAME} 引用。设置后必须同时提供 `password`(更新时省略 `password` 表示保留已保存的密码)。", "type": "string" } }, @@ -8282,7 +8568,7 @@ "type": "integer" }, "username": { - "description": "认证用户名,支持 ${env:NAME} 引用。", + "description": "认证用户名,支持 ${env:NAME} 引用。设置后必须同时提供 `password`(更新时省略 `password` 表示保留已保存的密码)。", "type": "string" } }, @@ -8608,7 +8894,7 @@ "type": "integer" }, "datasource_id": { - "description": "通过 /monit/datasource/list 获取的数据源 ID。", + "description": "要执行工具的数据源 ID,可从 `/monit/datasource/list` 获取。调用方需要拥有该数据源的查询权限。查询工具(`.query`)的 ID 不能超过 9007199254740991。", "format": "uint64", "minimum": 1, "type": "integer" @@ -8671,7 +8957,7 @@ "DatasourceToolTruncation": { "properties": { "reason": { - "description": "结果截断原因;该对象存在即表示发生截断。", + "description": "结果被截断的原因,由执行端 Edge 给出,请当作不透明字符串处理。仅当结果被截断时才返回该对象。", "type": "string" } }, @@ -8695,12 +8981,12 @@ "format": "int64", "minimum": 1, "maximum": 9007199254740991, - "description": "数据源 ID,来自 `/monit/datasource/list`。必须是正数且不超过 JavaScript 安全整数范围,且属于当前账户。" + "description": "来自 `/monit/datasource/list` 的数据源 ID。必须是正的 JavaScript 安全整数,对应已认证账户下已启用、且调用方有权查询的数据源。" }, "expr": { "type": "string", "minLength": 1, - "description": "使用数据源原生语言的查询表达式(如 PromQL、LogsQL、SQL 等)。非空 UTF-8 字符串,最长 64 KiB;部分数据源类型限制更小。" + "description": "使用数据源原生语言的查询表达式(PromQL、LogsQL、SQL 等)。非空 UTF-8,最大 64 KiB;`mysql` 最大 16 KiB,`tencent_cls` 最大 12 KiB。" }, "args": { "type": "object", @@ -8717,7 +9003,7 @@ }, "QueryExploreExecution": { "type": "object", - "description": "查询的时间语义。可接受的配套字段取决于 `kind`:`instant` 只需 `to_ms`(`from_ms` 可选),`range` 需要 `from_ms`、`to_ms` 和 `max_data_points`,`window` 需要 `from_ms` 和 `to_ms`。HTTP 接口不接受 `step_seconds`。", + "description": "查询的时间语义。可接受的配套字段取决于 `kind`:`instant` 使用 `to_ms`(可选 `from_ms`),`range` 需要 `from_ms`、`to_ms` 和 `max_data_points`,`window` 只使用 `from_ms` 与 `to_ms`。同时给出两个时间时,`from_ms` 必须小于 `to_ms`。HTTP 接口不接受 `step_seconds`。", "required": [ "kind" ], @@ -8729,17 +9015,19 @@ "range", "window" ], - "description": "执行类型。`instant` 在单个时间点取值,`range` 在时间范围内取序列,`window` 返回时间窗口内的原始行。" + "description": "执行类型。\n\n- `instant`:在单个时间点上求值。\n- `range`:在 `from_ms` 到 `to_ms` 范围内求时间序列,步长由 `max_data_points` 与 `min_step_seconds` 推导。\n- `window`:查询 `from_ms` 到 `to_ms` 之间的区间,不带步长。" }, "from_ms": { "type": "integer", "format": "int64", - "description": "范围起点的 Unix 毫秒时间戳。`range` 和 `window` 必填,`instant` 可选。" + "description": "区间起点,Unix 时间戳,单位毫秒;非负且小于 `to_ms`。`range` 与 `window` 必填,`instant` 可选。", + "minimum": 0 }, "to_ms": { "type": "integer", "format": "int64", - "description": "范围终点的 Unix 毫秒时间戳。所有执行类型均必填。" + "description": "区间终点(`instant` 时为求值时间),Unix 时间戳,单位毫秒;非负。所有执行类型都必填。", + "minimum": 0 }, "max_data_points": { "type": "integer", @@ -8800,7 +9088,7 @@ "items": { "$ref": "#/components/schemas/ExploreFrame" }, - "description": "列式 Frame 列表,`kind` 为 `frames` 时出现,最多 1,000 个。" + "description": "列式 frame。`kind` 为 `frames` 时返回;最多 1,000 个 frame,表格行合计最多 1,000 行,值合计最多 100,000 个。" }, "samples": { "type": "array", @@ -8818,7 +9106,7 @@ }, "applied_limit": { "type": "integer", - "description": "日志结果实际生效的条数上限,最大 1000。" + "description": "logs 结果实际应用的条数上限:1 到 1000(`sls` 数据源为 1 到 100)。仅在 `kind` 为 `logs` 时返回。" }, "has_more": { "type": "boolean", @@ -8840,7 +9128,7 @@ "table", "time_series" ], - "description": "Frame 形态。`table` 为无标签表格,`time_series` 恰好包含一个时间字段和一个 float 字段。" + "description": "Frame 形态。`table` 是不带标签的表格。`time_series` 恰好包含一个时间字段和一个 float 字段,时间值严格递增且不为 null。" }, "fields": { "type": "array", @@ -8883,7 +9171,18 @@ "values": { "type": "array", "items": { - "description": "单个单元格。`time` 为 UTC RFC3339Nano 字符串,`float` 可以是字符串 `NaN`、`+Inf`、`-Inf`,除 `time_series` 中的时间值外均可以为 null。" + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "null" + } + ], + "description": "单元格取值。`time` 单元格为 UTC RFC3339Nano 字符串;`float` 单元格可以是字符串 `NaN`、`+Inf`、`-Inf`;除 `time_series` frame 中的时间值外,任何单元格都可以为 null。" }, "description": "按行顺序排列的列取值。" } @@ -8905,7 +9204,15 @@ "description": "采样的标签集合。可以为空,但不能为 null。" }, "value": { - "description": "采样值:数字,或字符串 `NaN`、`+Inf`、`-Inf`。不能为 null。" + "oneOf": [ + { + "type": "number" + }, + { + "type": "string" + } + ], + "description": "采样值:数字,或字符串 `NaN`、`+Inf`、`-Inf` 之一。不会为 null。" } } }, @@ -9011,11 +9318,11 @@ "additionalProperties": { "type": "string" }, - "description": "自定义标签。" + "description": "附加到该规则每个告警事件上的自定义标签。键会去除首尾空白,不能为空,且不能以 `__alert_rule_` 开头(保留前缀);包含 `{{` 的值会在事件投递时按模板渲染;`job` 与 `instance` 的值最长 255 个字符。序列化后的对象不得超过 1024 个字符。" }, "ds_type": { "type": "string", - "description": "数据源类型标识(如 `prometheus`、`elasticsearch`)。" + "description": "规则查询的数据源类型。规则启用时必须是支持告警的类型:`prometheus`、`elasticsearch`、`loki`、`clickhouse`、`mysql`、`oracle`、`postgres`、`sls`、`tencent_cls`、`victorialogs`。" }, "ds_list": { "type": "array", @@ -9046,7 +9353,7 @@ }, "cron_pattern": { "type": "string", - "description": "调度表达式:6 段(含秒)cron 表达式或 `@every 30s` 间隔描述。不允许以 `CRON_TZ=` 或 `TZ=` 开头,时区请填写到 `timezone` 字段。" + "description": "调度表达式:6 段(含秒)cron 表达式(如 `0 * * * * *`)、`@hourly` 等描述符,或 `@every <时长>`(须为整数秒且不小于 `1s`,如 `@every 30s`)。不允许以 `CRON_TZ=` 或 `TZ=` 开头,时区请填写到 `timezone` 字段。" }, "timezone": { "type": "string", @@ -9083,15 +9390,15 @@ "items": { "type": "integer" }, - "description": "星期几(0=周日)。" + "description": "时间窗口适用的星期,`0` = 周日至 `6` = 周六;不能为空,不能重复。" }, "stime": { "type": "string", - "description": "开始时间,如 `09:00`。" + "description": "开始时间,24 小时制 `HH:MM` 格式,如 `09:00`。" }, "etime": { "type": "string", - "description": "结束时间,如 `18:00`。" + "description": "结束时间,24 小时制 `HH:MM` 格式,如 `18:00`。" } } } @@ -9114,7 +9421,7 @@ }, "description": { "type": "string", - "description": "规则描述,Markdown 格式。" + "description": "规则描述,按 `description_type` 以纯文本或 Markdown 渲染。" }, "channel_ids": { "type": "array", @@ -9127,12 +9434,12 @@ "repeat_interval": { "type": "integer", "format": "int64", - "description": "通知重复间隔(秒)。小于 1 时按默认值 3600 处理。" + "description": "通知重复间隔(秒)。小于 1 时按默认值 3600 处理,最大 2147483647。" }, "repeat_total": { "type": "integer", "format": "int64", - "description": "最大重复通知次数。小于 1 时按默认值 3 处理。" + "description": "最大重复通知次数。小于 1 时按默认值 3 处理,最大 2147483647。" }, "investigation_targets": { "type": "array", @@ -9140,7 +9447,7 @@ "$ref": "#/components/schemas/InvestigationTarget" }, "maxItems": 20, - "description": "告警事件详情页关联的排障入口列表,最多 20 项,不允许重复。更新接口中该字段按 presence 处理:省略时保留原配置,传 `[]` 清空。", + "description": "告警事件详情页关联的排障入口列表,最多 20 项,不允许重复,序列化后不超过 32 KiB。更新接口中该字段按 presence 处理:省略时保留原配置,传 `[]` 清空;传 `null` 会被拒绝。", "x-flashduty-preserve-absence": true }, "creator_id": { @@ -9225,7 +9532,7 @@ }, "relate_queries": { "type": "array", - "description": "可选的辅助查询,其结果作为上下文附加到告警事件中。每项须有唯一的 `name`(不与任何 query 名称重复)且 `expr` 非空。", + "description": "可选的辅助查询,其结果作为上下文附加到告警事件中。每项须有唯一的 `name`(不与任何 query 名称重复)且 `expr` 非空。响应中始终返回,没有时为 `[]`。", "items": { "type": "object", "properties": { @@ -9544,7 +9851,7 @@ }, "DashboardQuery": { "type": "object", - "description": "仪表盘与排障入口共用的查询内容。", + "description": "仪表盘面板与告警规则排障入口共用的查询内容。两种场景的模板语法不同:仪表盘面板引用仪表盘变量(`${name}`),排障入口引用事件标签(`{{ }}`)。", "properties": { "mode": { "type": "string", @@ -9553,18 +9860,18 @@ "range", "window" ], - "description": "求值模式:`instant` 在单个时间点求值,`range` 求值一条按步长采样的曲线,`window` 返回时间窗口内的原始数据。" + "description": "求值模式:`instant` = 在单个时间点求值;`range` = 在时间范围内按步长求值得到曲线;`window` = 返回时间范围内的原始数据行。Prometheus 与 Loki 面板接受 `instant` 或 `range`(Loki 的 `logs` 面板需要 `range`);MySQL 面板需要 `window`。" }, "expr": { "type": "string", - "description": "目标数据源语法下的查询表达式,可通过 `{{ }}` 模板引用事件标签。" + "description": "数据源语法下的查询表达式。在仪表盘面板中可以 `${name}`、`${name:raw}`(原样插入单个值)或 `${name:regex}`(多个值拼成正则多选)引用变量,在 Prometheus 与 Loki 中也可写 `$name`;需要字面量时写 `$${...}`。不带格式化符时,多选或 `all` 变量以及 `=~`/`!~` 中的值会以正则形式插入,因此不能用在 `=` 或 `!=` 之后。MySQL 查询不支持变量。在排障入口中,表达式可通过 `{{ }}` 模板引用事件标签。" }, "args": { "type": "object", "additionalProperties": { "type": "string" }, - "description": "命名查询参数,默认空对象。值按原样透传,不允许包含 `{{ }}` 模板。" + "description": "命名查询参数,默认空对象。在仪表盘面板中,除 Loki 与 MySQL 数据源外,值可使用 `${name}` 模板。在排障入口中,键和值都不允许包含 `{{ }}` 模板。" }, "min_step_seconds": { "type": [ @@ -9574,7 +9881,7 @@ "format": "int64", "minimum": 1, "maximum": 9007199254740, - "description": "最小步长(秒)。仅在 `mode` 为 `range` 时可用,且必须大于 0;省略或传 null 由服务端决定。" + "description": "最小步长(秒),必须大于 0。在排障入口中仅当 `mode` 为 `range` 时可用。省略或传 null 由服务端决定。" } }, "required": [ @@ -9585,7 +9892,7 @@ }, "DashboardDefinition": { "type": "object", - "description": "以可移植 `dashboard.v1` 文档形式存储的完整仪表盘内容。未知字段、重复字段、NaN/Inf、超范围数字与尾随值都会被拒绝;序列化后不得超过 1 MiB。", + "description": "以可移植 `dashboard.v1` 文档形式存储的完整仪表盘内容。未知字段、重复字段、尾随值以及超过 32 层的嵌套都会被拒绝,序列化后不得超过 1 MiB。上限:10 个 tab,每个 tab 10 个 section、30 个面板、100 条查询,每个仪表盘 100 个面板、300 条查询,20 个变量。", "properties": { "title": { "type": "string", @@ -9617,7 +9924,7 @@ "$ref": "#/components/schemas/DashboardVariable" }, "maxItems": 20, - "description": "仪表盘变量,最多 20 个。名称在定义内必须唯一且符合变量名正则。" + "description": "仪表盘变量,最多 20 个,名称唯一。变量之间可以相互引用,但不能形成循环。" }, "tabs": { "type": "array", @@ -9626,7 +9933,7 @@ }, "minItems": 1, "maxItems": 10, - "description": "Tab,1~10 个。标题唯一,且所有 tab/section ID 必须是整份定义内唯一的 canonical UUIDv7。" + "description": "Tab,1~10 个。所有 tab、section 与面板的 `id` 必须是整份定义内只出现一次的 canonical UUIDv7。Tab 标题无需唯一。" } }, "required": [ @@ -9681,7 +9988,7 @@ "type": "string", "minLength": 1, "maxLength": 189, - "description": "Tab 标题,1~189 个 Unicode 字符,在 tab 之间唯一。" + "description": "Tab 标题,去除首尾空白后 1~189 个 Unicode 字符。" }, "description": { "type": "string", @@ -9694,7 +10001,7 @@ "$ref": "#/components/schemas/DashboardPanel" }, "maxItems": 30, - "description": "直接放在该 tab 上的面板,最多 30 个。" + "description": "直接放在该 tab 上的面板。一个 tab 内顶层面板与各 section 面板合计最多 30 个,查询最多 100 条。" }, "sections": { "type": "array", @@ -9742,7 +10049,7 @@ "$ref": "#/components/schemas/DashboardPanel" }, "maxItems": 30, - "description": "该 section 内的面板,最多 30 个。" + "description": "该 section 内的面板;计入所在 tab 合计 30 个面板的上限。" } }, "required": [ @@ -9754,7 +10061,7 @@ }, "DashboardPanel": { "type": "object", - "description": "单个可视化面板。同一容器内的面板不得重叠;24 列网格在保存时校验。", + "description": "单个可视化面板。除 `text` 外所有类型都必须填写 `datasource_ref`,`text` 面板不允许填写。同一容器内的面板不得重叠;24 列网格在保存时校验。", "properties": { "id": { "type": "string", @@ -9849,17 +10156,18 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "数据源 ID。`kind` 为 `fixed` 时必填,为 `variable` 时禁止设置。" + "description": "数据源 ID。`kind` 为 `fixed` 时必填,为 `variable` 时禁止设置。", + "maximum": 9007199254740991 }, "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "数据源变量名。`kind` 为 `variable` 时必填,为 `fixed` 时禁止设置。" + "description": "同一份定义中某个 `datasource` 类型变量的名称。`kind` 为 `variable` 时必填,为 `fixed` 时不允许填写。" }, "datasource_type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", - "description": "数据源类型标识,例如 `prometheus`、`victorialogs`。" + "description": "数据源类型标识:以小写字母开头,由小写字母、数字和下划线组成。取值集合是开放的,保存时接受任何符合格式的值,但仪表盘运行时只支持 `prometheus`、`mysql`、`loki` 数据源;其他类型的面板在运行时会失败。`kind` 为 `variable` 时必须与所引用数据源变量的 `datasource_type` 一致。" } }, "required": [ @@ -9882,7 +10190,7 @@ "legend_alias": { "type": "string", "maxLength": 1024, - "description": "可选图例名;支持与 `expr` 相同的变量模板。" + "description": "可选图例名,最多 1024 个 Unicode 字符。控制台会把 `{{label}}` 替换为该序列对应标签的值(如 `{{env}} requests`);这里不会替换仪表盘变量。" } }, "required": [ @@ -9926,7 +10234,7 @@ "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "在 `{{ }}` 模板中引用的变量名,最多 64 个字符。以 `__` 开头的名称保留给内置时间变量。" + "description": "变量名,在定义内唯一。查询中以 `${name}` 引用(在 Prometheus 与 Loki 表达式中也可写 `$name`)。以 `__` 开头的名称保留给内置变量 `__interval`、`__rate_interval`、`__range`、`__auto`。" }, "label": { "type": "string", @@ -9936,7 +10244,7 @@ "datasource_type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", - "description": "候选项来自的数据源类型。" + "description": "作为候选项的数据源类型;候选项为账户下该类型的已启用数据源。取值集合是开放的,保存时接受任何符合格式的值,但仪表盘运行时只支持 `prometheus`、`mysql`、`loki` 数据源;其他类型的面板在运行时会失败。" }, "name_patterns": { "type": "array", @@ -9951,7 +10259,8 @@ "default_datasource_id": { "type": "integer", "format": "uint64", - "description": "默认数据源 ID。若默认值不可用,运行时按名称、再按 ID 取第一个候选项。" + "description": "默认数据源 ID。若默认值不可用,运行时按名称、再按 ID 取第一个候选项。", + "maximum": 9007199254740991 } }, "required": [ @@ -9974,7 +10283,7 @@ "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "在 `{{ }}` 模板中引用的变量名,最多 64 个字符。以 `__` 开头的名称保留给内置时间变量。" + "description": "变量名,在定义内唯一。查询中以 `${name}` 引用(在 Prometheus 与 Loki 表达式中也可写 `$name`)。以 `__` 开头的名称保留给内置变量 `__interval`、`__rate_interval`、`__range`、`__auto`。" }, "label": { "type": "string", @@ -10018,7 +10327,7 @@ "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "在 `{{ }}` 模板中引用的变量名,最多 64 个字符。以 `__` 开头的名称保留给内置时间变量。" + "description": "变量名,在定义内唯一。查询中以 `${name}` 引用(在 Prometheus 与 Loki 表达式中也可写 `$name`)。以 `__` 开头的名称保留给内置变量 `__interval`、`__rate_interval`、`__range`、`__auto`。" }, "label": { "type": "string", @@ -10079,7 +10388,7 @@ }, "DashboardSelection": { "type": "object", - "description": "变量取值的具体选择。空的 `values` 数组是合法输入,表示未解析——服务端不会为其回退到默认值。", + "description": "变量取值的具体选择。作为已保存变量的 `default` 时,`values` 不能为空,`single` 模式下必须恰好一个值。在运行时请求中,空的 `values` 数组是合法输入,表示未解析——服务端不会为其回退到默认值。", "properties": { "kind": { "type": "string", @@ -10166,7 +10475,7 @@ }, "metric": { "type": "string", - "description": "可选指标名,用于限定参与计算的序列。" + "description": "可选的指标选择器,用于限定参与计算的序列;可通过 `${name}` 或 `$name` 引用其他变量。" }, "label_filters": { "type": "array", @@ -10188,7 +10497,7 @@ "label": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_:.\\-]{0,189}$", - "description": "标签名。" + "description": "要匹配的 Prometheus 标签名,如 `job`;由字母、数字、`_`、`:`、`.`、`-` 组成,以字母或 `_` 开头。" }, "op": { "type": "string", @@ -10203,7 +10512,7 @@ "value": { "type": "string", "minLength": 1, - "description": "匹配值;可通过 `{{ }}` 引用其他变量。" + "description": "匹配值;可通过 `${name}` 引用其他变量。多选或含 `all` 的变量需搭配 `=~` 或 `!~`。" } }, "required": [ @@ -10225,7 +10534,7 @@ }, "expr": { "type": "string", - "description": "SQL 语句;可通过 `{{ }}` 引用其他变量。" + "description": "其结果作为候选项的 SQL 语句。SQL 变量查询只在 MySQL 数据源上运行,而 MySQL 查询不支持引用变量。" }, "args": { "type": "object", @@ -10264,7 +10573,7 @@ }, "expr": { "type": "string", - "description": "日志查询表达式;可通过 `{{ }}` 引用其他变量。数据源为 Loki 时可为空,此时会列出该字段在所有流中的取值。" + "description": "日志查询表达式;可通过 `${name}` 引用其他变量。日志变量查询只在 Loki 数据源上运行,此时 `expr` 可为空,表示列出该字段在所有流中的取值。" }, "args": { "type": "object", @@ -10287,7 +10596,7 @@ ] }, "DashboardVizConfig": { - "description": "可视化配置。`kind` 决定使用哪个分支以及哪个同级的配置对象必需;`time_series` 还携带通用的数值配置。", + "description": "可视化配置。`kind` 决定使用哪个分支,从而决定允许哪些同级字段;`time_series`、`stat`、`bar`、`gauge` 还带有通用数值字段 `unit`、`decimals`、`threshold`。出现其他类型的字段会被拒绝。", "oneOf": [ { "$ref": "#/components/schemas/DashboardTimeSeriesViz" @@ -10354,7 +10663,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。" + "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。省略时默认为 `unitless`。" }, "decimals": { "type": [ @@ -10362,7 +10671,8 @@ "null" ], "minimum": 0, - "description": "固定小数位;省略或传 null 由前端决定。" + "description": "固定小数位数,0~15;省略或传 null 由控制台决定。", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10394,15 +10704,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardColumnOption" }, - "description": "按字段名索引的列展示覆盖配置,最多 100 项。" + "description": "按结果字段名设置的列展示覆盖项,最多 100 项。键名不能为空,最多 1024 个 Unicode 字符,且不能是 `frame_index` 或 `field_index`。" }, "sort": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardFieldSort" }, - "maxItems": 2, - "description": "初始排序键;字段需唯一。" + "description": "初始排序键,按顺序生效;每个字段只能出现一次。" }, "link_columns": { "type": "array", @@ -10448,7 +10757,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。" + "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。省略时默认为 `unitless`。" }, "decimals": { "type": [ @@ -10456,7 +10765,8 @@ "null" ], "minimum": 0, - "description": "固定小数位;省略或传 null 由前端决定。" + "description": "固定小数位数,0~15;省略或传 null 由控制台决定。", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10466,7 +10776,9 @@ "items": { "type": "string" }, - "description": "被归约为展示取值的字段。" + "description": "归约为展示值的结果字段;至少一个且不可重复。按名称精确匹配,不能是 `frame_index` 或 `field_index`。", + "minItems": 1, + "uniqueItems": true }, "reducer": { "type": "string", @@ -10517,7 +10829,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。" + "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。省略时默认为 `unitless`。" }, "decimals": { "type": [ @@ -10525,21 +10837,25 @@ "null" ], "minimum": 0, - "description": "固定小数位;省略或传 null 由前端决定。" + "description": "固定小数位数,0~15;省略或传 null 由控制台决定。", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" }, "category_field": { "type": "string", - "description": "提供类目轴的字段。" + "description": "提供类目轴的结果字段;必填,最多 1024 个 Unicode 字符,不能是 `frame_index` 或 `field_index`。", + "minLength": 1 }, "value_fields": { "type": "array", "items": { "type": "string" }, - "description": "提供柱值的字段。" + "description": "提供柱值的结果字段;至少一个且不可重复。名称不能是 `frame_index` 或 `field_index`。", + "minItems": 1, + "uniqueItems": true }, "data_link": { "$ref": "#/components/schemas/DashboardDataLink" @@ -10582,7 +10898,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。" + "description": "面板数值的展示单位:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。省略时默认为 `unitless`。" }, "decimals": { "type": [ @@ -10590,7 +10906,8 @@ "null" ], "minimum": 0, - "description": "固定小数位;省略或传 null 由前端决定。" + "description": "固定小数位数,0~15;省略或传 null 由控制台决定。", + "maximum": 15 }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10600,7 +10917,9 @@ "items": { "type": "string" }, - "description": "被归约为仪表值的字段。" + "description": "归约为仪表值的结果字段;至少一个且不可重复。按名称精确匹配,不能是 `frame_index` 或 `field_index`。", + "minItems": 1, + "uniqueItems": true }, "reducer": { "type": "string", @@ -10683,7 +11002,7 @@ "markdown": { "type": "string", "maxLength": 65536, - "description": "Markdown 正文,最多 64 KiB。仅限白名单节点(标题、列表、表格、链接、代码)可通过校验。" + "description": "Markdown 正文,最多 64 KiB。允许段落、标题、列表、引用、代码块与行内代码、强调、表格、分隔线与链接。链接必须是 `https://` 地址或以 `/` 开头的站内相对路径。图片、原始 HTML 与 `${` 模板会以 `InvalidParameter` 拒绝,而不是被过滤掉。" } }, "required": [ @@ -10761,7 +11080,7 @@ "bytes_per_second", "bits_per_second" ], - "description": "列展示单位覆盖:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。" + "description": "列展示单位覆盖:`unitless` = 原始数值;`ratio` = 占比(0–1 的小数);`percent` = 百分比;`milliseconds` = 毫秒;`seconds` = 秒;`bytes` = 字节;`bits` = 比特;`count_per_second` = 每秒计数;`bytes_per_second` = 每秒字节数;`bits_per_second` = 每秒比特数。省略时默认为 `unitless`。" }, "threshold": { "$ref": "#/components/schemas/DashboardThreshold" @@ -10786,7 +11105,7 @@ "field": { "type": "string", "minLength": 1, - "description": "排序字段名。" + "description": "排序依据的结果字段名;最多 1024 个 Unicode 字符,不能是 `frame_index` 或 `field_index`。" }, "direction": { "type": "string", @@ -10804,12 +11123,12 @@ }, "DashboardDataLink": { "type": "object", - "description": "从表格列或柱状图面板下钻到另一个仪表盘的链接。目标仪表盘必须存在,且映射来源需与源面板的结构匹配。", + "description": "从表格或柱状图面板下钻到另一个仪表盘的链接。保存时只校验 ID 格式,指向不存在仪表盘的链接也会被接受。允许的映射来源取决于源面板类型。", "properties": { "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "目标仪表盘 ID。" + "description": "要打开的仪表盘 ID;必须是 canonical UUIDv7。" }, "target_id": { "type": "string", @@ -10825,7 +11144,7 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardLinkMapping" }, - "description": "把目标变量名映射到某个来源值,例如表格列或源变量。" + "description": "要在目标仪表盘中设置的变量值,键为目标变量名(需符合 `^[A-Za-z_][A-Za-z0-9_]{0,63}$`);每项说明取值来源。无映射时传 `{}`。" } }, "required": [ @@ -10847,15 +11166,15 @@ "series", "value" ], - "description": "取值来源:`variable` = 仪表盘变量;`row_column` = 表格列(必须同时给出 `column`);`category` = 柱状图的类目;`series` = 序列名;`value` = 数值本身。`category`、`series`、`value` 仅对柱状图面板有效。" + "description": "取值来源:`variable` = 源仪表盘某个变量的当前值(需填 `name`),表格与柱状图面板可用;`row_column` = 被点击行在某表格列的值(需填 `column`),仅表格面板;`category` = 被点击柱的类目,`series` = 其序列名,`value` = 其数值——这三种仅柱状图面板可用,且不带额外字段。" }, "column": { "type": "string", - "description": "来源列名;`source` 为 `row_column` 时必填。" + "description": "要读取的表格列(结果字段);`source` 为 `row_column` 时必填,否则不允许填写。" }, "name": { "type": "string", - "description": "来源仪表盘变量名;`source` 为 `variable` 时必填。" + "description": "要读取的源仪表盘变量;`source` 为 `variable` 时必填,且必须存在于同一份定义中;其他来源不允许填写。" } }, "required": [ @@ -10869,11 +11188,11 @@ "id": { "type": "integer", "format": "uint64", - "description": "成员 ID。" + "description": "执行该操作的成员 ID。" }, "name": { "type": "string", - "description": "成员展示名。" + "description": "成员展示名,记录于操作发生时。" } }, "required": [ @@ -10956,13 +11275,13 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "仪表盘 ID;传给 `POST /monit/dashboard/get` 可获取完整定义。" }, "folder_id": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "目录 ID。" + "description": "仪表盘所在目录的 ID。" }, "folder_breadcrumb": { "type": "array", @@ -10977,7 +11296,7 @@ }, "description": { "type": "string", - "description": "仪表盘描述;未设置时为空串。" + "description": "仪表盘描述;未设置时省略。" }, "revision": { "type": "integer", @@ -11033,7 +11352,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "回收站中仪表盘的 ID;可传给 `POST /monit/dashboard/restore`。" }, "folder_id": { "type": "integer", @@ -11054,13 +11373,13 @@ }, "description": { "type": "string", - "description": "仪表盘描述;未设置时为空串。" + "description": "仪表盘描述;未设置时省略。" }, "revision": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "删除时的版本号。" + "description": "回收站中该仪表盘的当前版本号(删除时已加 1);恢复时作为 `expected_revision` 传入。" }, "deleted_by": { "$ref": "#/components/schemas/DashboardActor" @@ -11095,7 +11414,7 @@ "total": { "type": "integer", "format": "int64", - "description": "已删除仪表盘总数。" + "description": "调用方可见的已删除仪表盘总数(跨所有分页)。" } }, "required": [ @@ -11105,11 +11424,11 @@ }, "DashboardUpdateOutput": { "type": "object", - "description": "更新或移动的结果。`changed` 为 false 表示本次写入是空操作——规范化后的序列化定义与已存内容逐字节相同,此时 `resource` 仍描述该未变化的仪表盘。", + "description": "更新或移动的结果。`changed` 为 false 表示未做任何写入——更新时规范化后的定义与 `schema_version` 均与已存内容相同;移动时仪表盘已在目标目录中。此时 `revision` 不变,`resource` 描述未变化的仪表盘。", "properties": { "changed": { "type": "boolean", - "description": "已存储的仪表盘是否真的发生了变化。" + "description": "是否发生了写入并使 `revision` 加 1。" }, "resource": { "$ref": "#/components/schemas/DashboardResource" @@ -11127,13 +11446,13 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "已移入回收站的仪表盘 ID。" }, "revision": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "本次删除记录的版本号。" + "description": "删除后的版本号;恢复时作为 `expected_revision` 传入。" } }, "required": [ @@ -11148,7 +11467,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "该版本所属的仪表盘 ID。" }, "revision": { "type": "integer", @@ -11165,7 +11484,7 @@ "message": { "type": "string", "maxLength": 1024, - "description": "可选提交说明;最多 1024 个 Unicode 字符。" + "description": "调用 `POST /monit/dashboard/update` 时传入的说明;未提供时,以及创建、移动、删除、恢复产生的版本上,此字段省略。" }, "actor": { "$ref": "#/components/schemas/DashboardActor" @@ -11207,7 +11526,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "该版本所属的仪表盘 ID。" }, "schema_version": { "type": "string", @@ -11234,7 +11553,7 @@ "message": { "type": "string", "maxLength": 1024, - "description": "可选提交说明。" + "description": "调用 `POST /monit/dashboard/update` 时传入的说明;未提供时省略。" }, "actor": { "$ref": "#/components/schemas/DashboardActor" @@ -11294,7 +11613,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "仪表盘 ID,与请求中传入的一致。" }, "title": { "type": "string", @@ -11302,7 +11621,7 @@ }, "description": { "type": "string", - "description": "仪表盘描述;未设置时为空串。" + "description": "仪表盘描述;未设置时省略。" }, "revision": { "type": "integer", @@ -11331,7 +11650,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "目录 ID。" + "description": "仪表盘所在目录的 ID。" }, "breadcrumb": { "type": "array", @@ -11357,7 +11676,7 @@ }, "label": { "type": "string", - "description": "展示名;未设置时为空串。" + "description": "展示名;未设置时省略。" }, "kind": { "type": "string", @@ -11384,15 +11703,15 @@ "id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Tab ID。" + "description": "Tab ID;作为 `target_id` 传入可把大纲收窄到该 tab。" }, "title": { "type": "string", - "description": "Tab 标题。" + "description": "定义中保存的 tab 标题。" }, "description": { "type": "string", - "description": "Tab 描述;未设置时为空串。" + "description": "Tab 描述;未设置时省略。" }, "breadcrumb": { "type": "array", @@ -11431,7 +11750,7 @@ "id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "Section ID。" + "description": "Section ID;作为 `target_id` 传入可把大纲收窄到该 section。" }, "title": { "type": "string", @@ -11439,7 +11758,7 @@ }, "description": { "type": "string", - "description": "Section 描述;未设置时为空串。" + "description": "Section 描述;未设置时省略。" }, "breadcrumb": { "type": "array", @@ -11470,7 +11789,7 @@ "id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "面板 ID。" + "description": "面板 ID;可作为 `POST /monit/dashboard/panel/run` 的 `panel_id`,或在此作为 `target_id`。" }, "title": { "type": "string", @@ -11478,7 +11797,7 @@ }, "description": { "type": "string", - "description": "面板描述;未设置时为空串。" + "description": "面板描述;未设置时省略。" }, "breadcrumb": { "type": "array", @@ -11492,7 +11811,7 @@ }, "datasource_type": { "type": "string", - "description": "面板查询的数据源类型;面板无数据源(text 面板)时为空串。" + "description": "面板 `datasource_ref` 中的数据源类型,如 `prometheus`、`mysql`、`loki`;text 面板没有数据源,此字段省略。取值集合是开放的,原样返回保存时的类型。" } }, "required": [ @@ -11558,7 +11877,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘的 canonical UUIDv7。" + "description": "由调用方生成的小写 canonical UUIDv7,作为仪表盘的永久 ID。" }, "schema_version": { "type": "string", @@ -11571,7 +11890,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "创建到哪个目录。必须是调用方有写权限的目录。" + "description": "创建到哪个目录;该目录必须存在且 `app_key` 所属成员可访问,否则返回 `FolderNotFound`。" }, "definition": { "$ref": "#/components/schemas/DashboardDefinition" @@ -11674,7 +11993,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "目标目录 ID。" + "description": "目标目录 ID;该目录必须存在且调用方可访问,否则返回 `FolderNotFound`。" } }, "required": [ @@ -11685,7 +12004,7 @@ }, "DashboardDeleteRequest": { "type": "object", - "description": "把仪表盘移入回收站。定义会保留 30 天,因此可用恢复接口撤销删除。", + "description": "把仪表盘移入回收站。删除 30 天后被永久清除;在此之前可用恢复接口撤销删除。", "properties": { "dashboard_id": { "type": "string", @@ -11717,7 +12036,7 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "调用方最后读到的版本号。若与已存版本不一致,写入会以 `DashboardRevisionConflict` 失败。" + "description": "回收站中该仪表盘的当前版本号,即删除接口返回或回收站列表中显示的值。不一致时以 `DashboardRevisionConflict` 失败。" }, "folder_id": { "type": [ @@ -11726,7 +12045,7 @@ ], "format": "uint64", "minimum": 1, - "description": "目标目录。省略则恢复到原目录;当原目录已不可写时调用会以 `RestoreFolderRequired` 失败,此时必须显式指定。" + "description": "目标目录。省略或传 null 表示恢复到原目录;若原目录已不存在,调用会以 `RestoreFolderRequired` 失败,此时必须指定目标目录。" } }, "required": [ @@ -11763,12 +12082,12 @@ "type": "integer", "format": "uint64", "minimum": 1, - "description": "要列出仪表盘的目录。" + "description": "要列出其直接包含的仪表盘的目录;不包含子目录。" }, "query": { "type": "string", "maxLength": 128, - "description": "可选空格分隔的搜索词,匹配标题与描述;最多 128 个 Unicode 字符。" + "description": "可选的搜索词,以空白分隔,最多 128 个 Unicode 字符。标题或描述中包含每一个词的仪表盘才会命中。" }, "sort": { "type": "array", @@ -11802,7 +12121,7 @@ "type": "string", "minLength": 1, "maxLength": 128, - "description": "空格分隔的搜索词;至少一个单词,最多 128 个 Unicode 字符。" + "description": "以空白分隔的搜索词;至少一个词,最多 128 个 Unicode 字符。标题或描述中包含每一个词的仪表盘才会命中。" }, "sort": { "type": "array", @@ -11861,13 +12180,15 @@ "type": "integer", "format": "int64", "minimum": 0, - "description": "Unix 时间戳(毫秒)。" + "description": "窗口起点,Unix 毫秒时间戳。须不小于 0 且小于 `to_ms`。", + "maximum": 9007199254740991 }, "to_ms": { "type": "integer", "format": "int64", "minimum": 1, - "description": "Unix 时间戳(毫秒)。" + "description": "窗口终点,Unix 毫秒时间戳。须大于 `from_ms`;`instant` 查询在该时间点求值。", + "maximum": 9007199254740991 } }, "required": [ @@ -11877,15 +12198,15 @@ }, "DashboardRuntimeError": { "type": "object", - "description": "变量级或查询级的失败。单个分支失败不会导致整个调用失败。", + "description": "单个变量或单条查询的失败。单个变量或查询失败不会导致整个调用失败。", "properties": { "reason": { "type": "string", - "description": "机器可读的失败原因。已观察到的取值包括 `invalid_request`、`variable_invalid`、`panel_missing`、`field_missing`、`datasource_permission_denied`、`timeout`、`panel_deadline`、`panel_canceled`、`canceled`、`overloaded`、`source_too_large`、`edge_unavailable`、`edge_upgrade_required`、`edge_version_unknown`、`mixed_edge_versions`、`internal`。" + "description": "机器可读的失败原因。取值集合是开放的,当前有:\n- `invalid_request`:查询或数据源配置被拒绝(数据源类型或查询模式不受支持、不允许 `args` 的地方传了参数、参数格式错误)。\n- `variable_invalid`:变量无法使用(既无选择也无默认值、所选值不在候选项中、依赖项未解析、替换出错、候选项列表不可用)。\n- `panel_missing`:面板不在该仪表盘中(仅出现在查询解析接口)。\n- `datasource_permission_denied`:数据源不存在、已停用、调用方无权访问,或没有可访问的数据源匹配该变量。\n- `field_missing`、`value_not_scalar`、`empty_field_name`、`duplicate_field_name`、`field_type_changed`:结果与面板可视化不匹配,或 SQL 变量查询返回了不可用的列。\n- `timeout`:数据源调用超时;`panel_deadline`:运行触达 35 秒总时限。\n- `canceled`、`panel_canceled`:调用被取消。\n- `overloaded`:数据源一侧正在限流。\n- `too_many_rows`、`result_too_large`、`source_too_large`:超出行数、大小或候选项数量上限。\n- `edge_unavailable`、`no_active_edge`、`edge_upgrade_required`、`edge_version_unknown`、`mixed_edge_versions`:数据源所属的 Edge 集群未连接、版本过旧、版本未知或版本混用。\n- `internal`:服务端意外错误。" }, "message": { "type": "string", - "description": "失败的可读详情。" + "description": "面向展示和排查的可读详情;措辞不保证稳定,请勿据此解析。" } }, "required": [ @@ -11895,18 +12216,18 @@ }, "DashboardRuntimeDatasource": { "type": "object", - "description": "运行时查询实际绑定的数据源。", + "description": "运行时变量或查询实际绑定的数据源。", "properties": { "id": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "数据源 ID。" + "description": "数据源 ID,与数据源列表接口返回的一致。" }, "type": { "type": "string", "pattern": "^[a-z][a-z0-9_]{0,63}$", - "description": "数据源类型标识。" + "description": "数据源类型标识。已解析的查询和 `query` 变量只会是 `prometheus`、`mysql` 或 `loki`;`datasource` 变量选中的数据源可以是该变量所配置的任意类型标识。" }, "name": { "type": "string", @@ -11921,12 +12242,12 @@ }, "DashboardResolvedVariable": { "type": "object", - "description": "单个已解析变量。数据源不可达、表达式错误或结果为空时,`candidates` 会不完整并填充 `error`,而不是让请求整体失败。", + "description": "单个已解析变量。出现失败(既无选择也无默认值、所选值不在候选项中、依赖项未解析、数据源不可达、查询结果不可用)时,会填充 `error` 并省略 `selection`,而不是让请求整体失败。", "properties": { "name": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,63}$", - "description": "变量名。" + "description": "变量名,与仪表盘或草稿中的定义一致。" }, "kind": { "type": "string", @@ -11942,7 +12263,7 @@ "items": { "$ref": "#/components/schemas/DashboardCandidate" }, - "description": "解析出的候选项,最多 1000 个。" + "description": "可选项,最多 1000 个;没有候选项或解析失败时为空数组。顺序:`custom` 保持定义顺序,`datasource` 按名称再按 ID 排序,`query` 按值排序。" }, "selection": { "$ref": "#/components/schemas/DashboardSelection" @@ -11977,13 +12298,13 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "已做出的选择,按变量名索引,最多 20 项。未在此给出的变量回退到其存储的默认值。" + "description": "已做出的选择,按变量名索引,最多 20 项。未给出的变量回退到其存储的默认值;出现仪表盘未定义的变量名时,调用以 HTTP 400 失败。", + "maxProperties": 20 } }, "required": [ "dashboard_id", - "time", - "variables" + "time" ] }, "DashboardVariablesResolveResponse": { @@ -11993,7 +12314,7 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "变量所属的仪表盘 ID,与请求一致。" }, "revision": { "type": "integer", @@ -12030,7 +12351,7 @@ "ref_id": { "type": "string", "pattern": "^[A-Z]$", - "description": "面板内的查询引用名。" + "description": "面板内的查询引用名:单个字母 `A`–`Z`。" }, "datasource": { "$ref": "#/components/schemas/DashboardRuntimeDatasource" @@ -12042,27 +12363,24 @@ "instant", "window" ], - "description": "求值模式:`range` = 按步长采样的时序;`instant` = 单个时间点;`window` = 有界时间窗口内的原始行。" + "description": "求值模式:`range` = 按步长采样的时序;`instant` = 单个时间点;`window` = 有界时间窗口内的行。Prometheus、Loki 查询使用 `range` 或 `instant`;MySQL 查询使用 `window`。" }, "expr": { "type": "string", - "description": "已完成变量替换的表达式。" + "description": "已完成变量替换的表达式。请求中 `preserve_builtin_variables` 为 `true` 时,内置时间变量原样保留。" }, "args": { "type": "object", "additionalProperties": { "type": "string" }, - "description": "查询参数;无参数时为空对象。" + "description": "查询参数;无参数时为空对象。只有 Loki 查询带参数:`loki.limit`(1~1000 的十进制整数,日志条数上限)和 `loki.direction`(`latest` 或 `earliest`)。" }, "min_step_seconds": { - "type": [ - "integer", - "null" - ], + "type": "integer", "format": "int64", "minimum": 1, - "description": "最小步长(秒);未设置时为 null。" + "description": "面板查询设置的最小步长(秒);未设置时不返回。" } }, "required": [ @@ -12075,12 +12393,12 @@ }, "DashboardResolvedPanelQueries": { "type": "object", - "description": "单个面板的解析结果。所有查询都成功时 `state` 为 `success`,部分成功为 `partial`,全部失败为 `error`。", + "description": "单个面板的解析结果。所有查询都成功时 `state` 为 `success`,部分成功为 `partial`,全部失败为 `error`。`error` 只描述第一个失败。", "properties": { "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "面板 ID。" + "description": "面板 ID,与 `panel_ids` 中的某一项一致。" }, "state": { "type": "string", @@ -12089,14 +12407,14 @@ "partial", "error" ], - "description": "该面板查询的整体状态:`success` = 全部查询解析成功;`partial` = 部分成功;`error` = 全部失败。" + "description": "该面板查询的解析状态:`success` = 全部查询解析成功;`partial` = 部分成功、部分失败;`error` = 全部失败,包括面板不存在的情况。" }, "queries": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardResolvedQuery" }, - "description": "解析成功的查询。" + "description": "解析成功的查询,顺序与面板中的查询一致。失败的查询不出现;全部失败时为空数组。" }, "error": { "$ref": "#/components/schemas/DashboardRuntimeError" @@ -12135,7 +12453,8 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "按变量名索引的选择,最多 20 项。" + "description": "按变量名索引的选择,最多 20 项。未给出的变量回退到存储的默认值;出现仪表盘未定义的变量名时,调用以 HTTP 400 失败。", + "maxProperties": 20 }, "max_data_points": { "type": [ @@ -12144,7 +12463,7 @@ ], "minimum": 2, "maximum": 5000, - "description": "用于计算 step 并渲染内置时间变量的降采样目标,2~5000 个点;省略或传 null 时服务端默认 100。" + "description": "每条序列的目标最大点数,用于计算步长并渲染内置时间变量。取值 2~5000;省略或传 null 时默认 100。" }, "preserve_builtin_variables": { "type": "boolean", @@ -12154,18 +12473,17 @@ "required": [ "dashboard_id", "panel_ids", - "time", - "variables" + "time" ] }, "DashboardQueriesResolveResponse": { "type": "object", - "description": "每个请求的面板对应一个条目,顺序与请求一致。", + "description": "所请求面板的已解析查询,以及解析时采用的生效变量选择。不会执行任何查询。", "properties": { "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "查询所依据的仪表盘 ID,与请求一致。" }, "revision": { "type": "integer", @@ -12181,14 +12499,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "解析成功的变量选择。" + "description": "解析成功的变量的生效选择,按变量名索引;解析失败的变量不出现。" }, "panels": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardResolvedPanelQueries" }, - "description": "每个面板的结果。" + "description": "每个请求的面板对应一个条目,顺序与请求一致。" } }, "required": [ @@ -12206,12 +12524,12 @@ "max_concurrency": { "type": "integer", "minimum": 1, - "description": "该面板查询的并发上限。" + "description": "该面板同时执行的查询数上限;固定为 6。" }, "execution_count": { "type": "integer", "minimum": 0, - "description": "发起的查询数量。" + "description": "解析成功并被派发执行的查询数量;解析失败的查询不计入。" } }, "required": [ @@ -12221,12 +12539,12 @@ }, "DashboardPanelRunRef": { "type": "object", - "description": "面板运行中单条查询的结果。原始执行载荷随数据源类型而异且原样透传,因此此处不做 schema 约束。", + "description": "面板运行或预览中单条查询的结果。原始执行载荷随数据源类型而异且原样透传,因此此处不做 schema 约束。", "properties": { "ref_id": { "type": "string", "pattern": "^[A-Z]$", - "description": "面板内的查询引用名。" + "description": "面板内的查询引用名:单个字母 `A`–`Z`,与面板 `queries` 中的设置一致。" }, "state": { "type": "string", @@ -12235,16 +12553,16 @@ "error", "incompatible" ], - "description": "单条查询的执行状态:`success` = 查询执行成功;`error` = 查询执行失败;`incompatible` = 数据源接受了调用,但查询模式或字段选择与该数据源类型不匹配。" + "description": "单条查询的状态:`success` = 查询已执行,且带有 `execution`;`error` = 查询无法解析或执行,或运行被取消、超时,原因见 `error`;`incompatible` = 查询已执行,但结果与面板可视化不匹配(例如配置的字段缺失或不是数值),此时仍带有 `execution`,`error` 说明不匹配的原因。" }, "child_request_id": { "type": "string", - "description": "底层数据源执行的请求 ID;排查单条查询时可用。" + "description": "底层数据源执行的请求 ID;排查单条查询时可用。查询没有到达数据源时不返回。" }, "execution": { "type": "object", "additionalProperties": true, - "description": "数据源专属的执行载荷,原样透传。" + "description": "数据源专属的执行结果,原样透传。`state` 为 `success` 或 `incompatible` 时存在,`error` 时不返回。" }, "error": { "$ref": "#/components/schemas/DashboardRuntimeError" @@ -12257,7 +12575,7 @@ }, "DashboardPanelRunRequest": { "type": "object", - "description": "对已存仪表盘执行某个面板。省略 `revision` 表示按当前版本运行;传入它可拒绝过期响应。", + "description": "执行已存仪表盘的某个面板。省略 `revision`(或传 0)表示按当前版本运行;传入它可让过期调用被拒绝。文本面板不能运行。", "properties": { "dashboard_id": { "type": "string", @@ -12267,13 +12585,12 @@ "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "要执行的面板。" + "description": "要执行的面板 ID。必须属于该仪表盘,否则返回 `TargetNotFound`(HTTP 404)。" }, "revision": { "type": "integer", "format": "uint64", - "minimum": 1, - "description": "版本护栏;设置时必须等于当前版本号。" + "description": "版本护栏。设置(非 0)时必须等于仪表盘当前版本号,否则以 `DashboardRevisionConflict`(HTTP 409)失败。省略或传 0 表示不校验。" }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12283,7 +12600,8 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "按变量名索引的选择,最多 20 项。" + "description": "按变量名索引的选择,最多 20 项。未给出的变量回退到存储的默认值;出现仪表盘未定义的变量名时,调用以 HTTP 400 失败。", + "maxProperties": 20 }, "max_data_points": { "type": [ @@ -12292,29 +12610,28 @@ ], "minimum": 2, "maximum": 5000, - "description": "降采样目标,2~5000 个点;省略或传 null 时服务端默认 100。" + "description": "`range` 查询每条序列的目标最大点数,服务端据此推算查询步长。取值 2~5000;省略或传 null 时默认 100。" } }, "required": [ "dashboard_id", "panel_id", - "time", - "variables" + "time" ] }, "DashboardPanelRunResponse": { "type": "object", - "description": "面板执行结果。`run_state` 汇总各查询状态:全部成功为 `success`,部分成功为 `partial`,否则为 `incompatible`、`cancelled` 或 `error`。整个响应上限 8 MiB。", + "description": "面板执行结果。即使所有查询都失败也返回 HTTP 200,请查看 `run_state` 以及各 ref 的 `state`、`error`。响应超过 8 MiB 时以 `EntityTooLarge`(HTTP 413)拒绝,而不会截断。", "properties": { "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "仪表盘 ID。" + "description": "被运行的仪表盘 ID,与请求一致。" }, "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "面板 ID。" + "description": "被运行的面板 ID,与请求一致。" }, "revision": { "type": "integer", @@ -12331,7 +12648,7 @@ "cancelled", "error" ], - "description": "本次运行的整体状态:`success` = 全部查询成功;`partial` = 部分成功;`incompatible` = 至少一条查询与其数据源类型不兼容;`cancelled` = 运行被取消;`error` = 全部查询失败。" + "description": "本次运行的整体状态:`success` = 全部查询成功;`partial` = 至少一个查询成功且至少一个未成功;`cancelled` = 没有查询成功,且客户端取消了请求;`incompatible` = 没有查询成功,且至少一个查询已执行但结果与面板可视化不匹配;`error` = 没有查询成功且没有 `incompatible`(面板没有查询时也是 `error`)。" }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12341,14 +12658,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "解析成功的变量选择。" + "description": "解析成功的变量的生效选择,按变量名索引;解析失败的变量不出现。" }, "refs": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardPanelRunRef" }, - "description": "面板中每条查询对应一个条目。" + "description": "面板中每条查询对应一个条目,顺序与面板中的查询一致。解析失败的查询以 `state` 为 `error` 出现。" }, "display": { "$ref": "#/components/schemas/DashboardVizConfig" @@ -12384,13 +12701,13 @@ "dashboard_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "`existing` 时必填,`new` 时禁止设置。" + "description": "`existing` 时必填,`new` 时禁止设置。调用方须能访问该仪表盘所在目录。" }, "folder_id": { "type": "integer", "format": "uint64", "minimum": 1, - "description": "`new` 时必填,`existing` 时禁止设置。" + "description": "`new` 时必填,`existing` 时禁止设置。须是调用方可访问的目录,否则返回 `FolderNotFound`(HTTP 404)。" } }, "required": [ @@ -12410,14 +12727,15 @@ "$ref": "#/components/schemas/DashboardVariable" }, "maxItems": 20, - "description": "草稿变量,最多 20 个。" + "description": "草稿变量,最多 20 个。按与已存定义相同的规则校验(名称、依赖、选项上限),且不得超过 1 MiB。" }, "selections": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "按变量名索引的选择,最多 20 项。" + "description": "按变量名索引的选择,最多 20 项。未给出的变量回退到其草稿默认值;出现不在 `variables` 中的变量名时,调用以 HTTP 400 失败。", + "maxProperties": 20 }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12426,7 +12744,6 @@ "required": [ "context", "variables", - "selections", "time" ] }, @@ -12439,14 +12756,14 @@ "items": { "$ref": "#/components/schemas/DashboardResolvedVariable" }, - "description": "已解析的变量。" + "description": "已解析的变量,顺序与草稿 `variables` 一致。" }, "selections": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "按变量名索引的生效选择。" + "description": "按变量名索引的生效选择;只包含解析成功的变量。" } }, "required": [ @@ -12456,7 +12773,7 @@ }, "DashboardPanelPreviewRequest": { "type": "object", - "description": "内联执行一个草稿面板,不会产生仪表盘新版本。同样受 1 MiB 定义体积上限约束。", + "description": "内联执行一个草稿面板,不会产生仪表盘新版本。草稿 `panel` 与 `variables` 合计不得超过 1 MiB,请求体不得超过 2 MiB。", "properties": { "context": { "$ref": "#/components/schemas/DashboardDraftContext" @@ -12470,14 +12787,15 @@ "$ref": "#/components/schemas/DashboardVariable" }, "maxItems": 20, - "description": "该面板可能引用的草稿变量。" + "description": "该面板可引用的草稿变量,最多 20 个。必填;面板查询只能使用此处列出的变量。" }, "selections": { "type": "object", "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "按变量名索引的选择。" + "description": "按变量名索引的选择,最多 20 项。未给出的变量回退到其草稿中的默认值。", + "maxProperties": 20 }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12489,25 +12807,24 @@ ], "minimum": 2, "maximum": 5000, - "description": "降采样目标,2~5000 个点。" + "description": "`range` 查询每条序列的目标最大点数,服务端据此推算查询步长。取值 2~5000;省略或传 null 时默认 100。" } }, "required": [ "context", "panel", "variables", - "selections", "time" ] }, "DashboardPanelPreviewResponse": { "type": "object", - "description": "草稿面板执行结果。与已存面板运行结构相同,只是不含仪表盘标识。", + "description": "草稿面板执行结果。与已存面板运行结构相同,只是不含 `dashboard_id` 和 `revision`。即使所有查询都失败也返回 HTTP 200;响应超过 8 MiB 时以 `EntityTooLarge`(HTTP 413)拒绝。", "properties": { "panel_id": { "type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$", - "description": "面板 ID。" + "description": "草稿面板的 ID,与请求中的 `panel.id` 相同。" }, "run_state": { "type": "string", @@ -12518,7 +12835,7 @@ "cancelled", "error" ], - "description": "本次运行的整体状态:`success` = 全部查询成功;`partial` = 部分成功;`incompatible` = 至少一条查询与其数据源类型不兼容;`cancelled` = 运行被取消;`error` = 全部查询失败。" + "description": "本次运行的整体状态:`success` = 全部查询成功;`partial` = 至少一个查询成功且至少一个未成功;`cancelled` = 没有查询成功,且客户端取消了请求;`incompatible` = 没有查询成功,且至少一个查询已执行但结果与面板可视化不匹配;`error` = 没有查询成功且没有 `incompatible`(面板没有查询时也是 `error`)。" }, "time": { "$ref": "#/components/schemas/DashboardAbsoluteTimeRange" @@ -12528,14 +12845,14 @@ "additionalProperties": { "$ref": "#/components/schemas/DashboardSelection" }, - "description": "解析成功的变量选择。" + "description": "解析成功的变量的生效选择,按变量名索引;解析失败的变量不出现。" }, "refs": { "type": "array", "items": { "$ref": "#/components/schemas/DashboardPanelRunRef" }, - "description": "面板中每条查询对应一个条目。" + "description": "面板中每条查询对应一个条目,顺序与面板中的查询一致。解析失败的查询以 `state` 为 `error` 出现。" }, "display": { "$ref": "#/components/schemas/DashboardVizConfig" @@ -12556,12 +12873,12 @@ }, "FolderItem": { "type": "object", - "description": "监控节点(目录)。目录构成树;`parent_path` 是以逗号分隔的祖先 ID 列表,调用方可据此在客户端重建树并自行搜索。", + "description": "监控文件夹。文件夹构成一棵树;`parent_path` 是以逗号分隔的祖先 ID 列表,调用方可据此重建树并在客户端搜索。", "properties": { "id": { "type": "integer", "format": "uint64", - "description": "目录 ID。" + "description": "文件夹 ID。更新、移动、删除该文件夹时作为 `id` 传入;在其下嵌套文件夹时作为 `parent_id` 或 `dest_parent_id`;告警规则和仪表盘上的 `folder_id` 也使用该值。" }, "account_id": { "type": "integer", @@ -12580,7 +12897,7 @@ "team_id": { "type": "integer", "format": "uint64", - "description": "目录归属的团队;账户级时为 0。" + "description": "文件夹所属团队的 ID;未归属任何团队时为 0。团队成员可以查看和修改该文件夹。" }, "name": { "type": "string", @@ -12593,7 +12910,7 @@ "creator_id": { "type": "integer", "format": "uint64", - "description": "创建者成员 ID。" + "description": "创建者的成员 ID;创建者始终可以查看和修改该文件夹。" }, "creator_name": { "type": "string", @@ -12602,7 +12919,7 @@ "updater_id": { "type": "integer", "format": "uint64", - "description": "最后更新者成员 ID。" + "description": "最后更新人的成员 ID。更新和移动都会写入该值。" }, "updater_name": { "type": "string", @@ -12611,12 +12928,12 @@ "created_at": { "type": "integer", "format": "int64", - "description": "Unix 时间戳(秒)。" + "description": "创建时间,Unix 时间戳,单位秒。" }, "updated_at": { "type": "integer", "format": "int64", - "description": "Unix 时间戳(秒)。" + "description": "最后一次更新或移动的时间,Unix 时间戳,单位秒。" } }, "required": [ @@ -12637,26 +12954,26 @@ }, "FolderCreateRequest": { "type": "object", - "description": "监控目录请求。", + "description": "创建监控文件夹的请求。", "properties": { "name": { "type": "string", - "description": "目录名称;不能包含句点、斜杠或逗号。", + "description": "文件夹名称;必填,不能包含句点(`.`)、斜杠(`/`)或逗号(`,`)。", "minLength": 1 }, "note": { "type": "string", - "description": "备注;更新时省略或传空字符串会清空备注。" + "description": "自由格式的备注。省略时为空。" }, "parent_id": { "type": "integer", - "description": "父目录 ID;0 或省略时创建顶层目录。", + "description": "父文件夹 ID;为 0 或省略时创建根文件夹。调用方必须有权修改该父文件夹。", "format": "uint64", "minimum": 0 }, "team_id": { "type": "integer", - "description": "团队 ID;0 表示账户范围。更新时省略会重置为 0。", + "description": "文件夹所属团队的 ID;为 0 或省略表示不归属任何团队。团队成员可以查看和修改该文件夹及其下的全部内容。", "format": "uint64", "minimum": 0 } @@ -12667,26 +12984,26 @@ }, "FolderUpdateRequest": { "type": "object", - "description": "监控目录请求。", + "description": "更新监控文件夹的请求。可编辑字段会整体替换。", "properties": { "id": { "type": "integer", - "description": "目录 ID。", + "description": "要更新的文件夹 ID,来自 `/monit/folder/list` 或创建响应。", "format": "uint64", "minimum": 1 }, "name": { "type": "string", - "description": "目录名称;不能包含句点、斜杠或逗号。", + "description": "新的文件夹名称;必填,不能包含句点(`.`)、斜杠(`/`)或逗号(`,`)。", "minLength": 1 }, "note": { "type": "string", - "description": "备注;更新时省略或传空字符串会清空备注。" + "description": "新的备注。省略或为空会清空备注。" }, "team_id": { "type": "integer", - "description": "团队 ID;0 表示账户范围。更新时省略会重置为 0。", + "description": "新的团队 ID;为 0 或省略会移除团队归属。", "format": "uint64", "minimum": 0 } @@ -12698,17 +13015,17 @@ }, "FolderMoveRequest": { "type": "object", - "description": "监控目录请求。", + "description": "移动监控文件夹及其后代的请求。", "properties": { "id": { "type": "integer", - "description": "目录 ID。", + "description": "要移动的文件夹 ID,来自 `/monit/folder/list`。", "format": "uint64", "minimum": 1 }, "dest_parent_id": { "type": "integer", - "description": "目标父目录 ID;移至顶层时必须显式传 0。", + "description": "新的父文件夹 ID;传 0 表示移至根级别。该字段不能省略。不能等于 `id`,也不能是该文件夹的后代。", "format": "uint64", "minimum": 0 } @@ -12720,11 +13037,11 @@ }, "FolderDeleteRequest": { "type": "object", - "description": "监控目录请求。", + "description": "删除监控文件夹的请求。", "properties": { "id": { "type": "integer", - "description": "目录 ID。", + "description": "要删除的文件夹 ID,来自 `/monit/folder/list`。该文件夹必须为空。", "format": "uint64", "minimum": 1 } @@ -12739,13 +13056,13 @@ "properties": { "folder_id": { "type": "integer", - "description": "目录 ID。", + "description": "该项所描述的文件夹 ID,与 `/monit/folder/list` 中的 `id` 对应。", "format": "uint64", "minimum": 0 }, "has_issue": { "type": "boolean", - "description": "本目录或可见后代目录是否存在活跃告警或规则运行问题。" + "description": "文件夹自身或任一后代文件夹中的规则存在活跃告警或运行问题(`runtime_state` 为 `offline`、`abnormal`、`stale` 或 `no_datasource`)时为 `true`。调用方不可读文件夹中的规则不计入。" } }, "required": [ @@ -12759,7 +13076,7 @@ "properties": { "items": { "type": "array", - "description": "目录摘要列表。", + "description": "调用方可见的每个文件夹对应一项健康摘要,按 `folder_id` 升序排列。", "items": { "$ref": "#/components/schemas/FolderHealthItem" } diff --git a/api-reference/on-call.openapi.en.json b/api-reference/on-call.openapi.en.json index 3f68fcbff..bd1132a3d 100644 --- a/api-reference/on-call.openapi.en.json +++ b/api-reference/on-call.openapi.en.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "Flashduty Open API", - "description": "Public HTTP API for the Flashduty incident management platform — incidents, notification templates, channels, schedules, monitors, RUM, and platform administration. Every operation is authenticated with an `app_key` query parameter issued from the Flashduty console under Account → APP Keys. Responses follow a uniform envelope: `{ request_id, data }` on success, `{ request_id, error }` on failure.", + "description": "Public HTTP API for the Flashduty incident management platform — incidents, notification templates, channels, schedules, monitors, RUM, and platform administration. Every operation is authenticated with an `app_key` query parameter created in the Flashduty console under My → APP Key (or sent in the `Fd-App-Key` header). Responses follow a uniform envelope: `{ request_id, data }` on success, `{ request_id, error }` on failure.", "version": "1.0.0" }, "servers": [ @@ -75,12 +75,12 @@ "post": { "operationId": "channelInhibitRuleDelete", "summary": "Delete inhibit rule", - "description": "Delete an inhibit rule. Only a `disabled` rule can be deleted.", + "description": "Delete a disabled inhibit rule so it no longer appears in the channel's rule list.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` rule can be deleted; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-inhibit-rule-delete", "metadata": { "sidebarTitle": "Delete inhibit rule" @@ -119,6 +119,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -151,7 +154,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- When `orderby` is omitted, types come back in console ranking order and `p`/`limit` still apply.\n- `supports_api_create` tells you which types `POST /integration/create` accepts.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- When `orderby` is omitted, types come back in console ranking order and `p`/`limit` still apply.\n- `supports_api_create` tells you which types `POST /integration/create` accepts.\n- `category` values are not validated; an unknown value returns an empty list.", "href": "/en/api-reference/on-call/integrations/integration-api-read-type-list", "metadata": { "sidebarTitle": "List integration types" @@ -212,6 +215,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -245,7 +251,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- `orderby` defaults to `created_at`; `plugin_type` is sorted by the underlying plugin.\n- `plugin_type`, `status` and `category` accept comma-separated values; `ref_ids` values must start with `c_`, `a_` or `w_`; a `c_` filter is syntactically accepted but does not return channel-owned integrations.\n- With `is_my_team` set, results are limited to your teams and `team_ids` narrows that set further.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Items include `settings`, `integration_key`, `plugin_id`, `account_id`, and the legacy `data_source_id` alias. Saved secret values in `settings` are returned as `******`; `integration_key` is returned as is.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- `orderby` defaults to `created_at`; `plugin_type` sorts by the underlying plugin. Rows are ordered by `ref_id` first, so `orderby` applies within each `ref_id` group.\n- `plugin_type`, `status` and `category` accept comma-separated values; `ref_ids` values must start with `c_`, `a_` or `w_`; a `c_` filter is syntactically accepted but does not return channel-owned integrations.\n- With `is_my_team` set, results are limited to your teams and `team_ids` narrows that set further; when you belong to no team, or `team_ids` shares no team with yours, the list is empty.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Items include `settings`, `integration_key`, `plugin_id`, `account_id`, and the legacy `data_source_id` alias. Saved secret values in `settings` are returned as `******`; `integration_key` is returned as is.", "href": "/en/api-reference/on-call/integrations/integration-api-read-list", "metadata": { "sidebarTitle": "List integrations" @@ -317,6 +323,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -350,7 +359,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Saved secret values in `settings` are returned as `******`, and unset ones stay empty. The integration key is returned as is.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Saved secret values in `settings` are returned as `******`, and unset ones stay empty. The integration key is returned as is.\n- An unknown ID, or the ID of a channel-owned integration, returns `ResourceNotFound`.", "href": "/en/api-reference/on-call/integrations/integration-api-read-info", "metadata": { "sidebarTitle": "Get integration detail" @@ -412,6 +421,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -443,7 +455,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- `plugin_type` must be one of the types listed by `POST /integration/type/list` with `supports_api_create: true`; anything else returns `InvalidParameter`.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- An omitted `integration_key` is generated automatically; a supplied key must satisfy the length, account suffix, and uniqueness checks.\n- With `is_test: true`, inspect `test.success`; an HTTP 200 response alone does not establish that the plugin test succeeded.\n- Every call is recorded in the account audit log.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- `plugin_type` must be one of the types listed by `POST /integration/type/list` with `supports_api_create: true`; anything else returns `InvalidParameter`.\n- A type whose `status` is `disabled` returns `InvalidParameter`; a type not included in the account's plan returns `NoLicense`.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- An omitted `integration_key` is generated automatically; a supplied key must satisfy the length, account suffix, and uniqueness checks.\n- With `is_test: true`, inspect `test.success`; an HTTP 200 response alone does not establish that the plugin test succeeded.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/integrations/integration-api-write-create", "metadata": { "sidebarTitle": "Create integration" @@ -489,6 +501,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -528,7 +543,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Only the fields you send are changed; omitted fields keep their current value.\n- Submitting `settings` replaces the configuration; known sensitive fields omitted or sent as `******` retain their value. Keeping a stored secret while changing where it is sent (such as `endpoint`, `url`, a database host or port, or an IM API base URL) is rejected, so send the secrets again with the new destination; `******` on a field with no stored value is rejected too. Send `headers: {}` to clear headers; use the integration type’s explicit empty value to clear a body.\n- Submit `settings` together with `is_test: true` to receive a plugin test result; secrets in the returned settings are masked the same way.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Write access also requires object permission: the account owner, an administrator, the creator, or a member of the assigned team; with no team, members with Integrations Manage may operate. Read-only integrations cannot be changed.\n- Every call is recorded in the account audit log.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Only the fields you send are changed; omitted fields keep their current value.\n- Submitting `settings` replaces the configuration; known sensitive fields omitted or sent as `******` retain their value. Keeping a stored secret while changing where it is sent (such as `endpoint`, `url`, a database host or port, or an IM API base URL) is rejected, so send the secrets again with the new destination; `******` on a field with no stored value is rejected too. Send `headers: {}` to clear headers; use the integration type’s explicit empty value to clear a body.\n- Submit `settings` together with `is_test: true` to receive a plugin test result; secrets in the returned settings are masked the same way.\n- If another request changes the same integration's settings while this one is being processed, the call returns `RequestLocked`; retry it. A type no longer included in the account's plan returns `NoLicense`.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Write access also requires object permission: the account owner, an administrator, the creator, or a member of the assigned team; with no team, members with Integrations Manage may operate. Read-only integrations cannot be changed.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/integrations/integration-api-write-update", "metadata": { "sidebarTitle": "Update integration" @@ -594,6 +609,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -671,6 +689,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -702,7 +723,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Enabling an integration resumes its scheduled pull task and heartbeat, and requires the integration type to be available on the current plan.\n- Every call is recorded in the account audit log.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Write access also requires object permission: the account owner, an administrator, the creator, or a member of the assigned team; with no team, members with Integrations Manage may operate. Read-only integrations cannot be changed.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Enabling an integration resumes its scheduled pull task and heartbeat, and requires the integration type to be available on the current plan.\n- Enabling an integration that is already enabled succeeds without change; the same holds for disabling a disabled one.\n- Every call is recorded in the account audit log.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Write access also requires object permission: the account owner, an administrator, the creator, or a member of the assigned team; with no team, members with Integrations Manage may operate. Read-only integrations cannot be changed.", "href": "/en/api-reference/on-call/integrations/integration-api-write-enable", "metadata": { "sidebarTitle": "Enable integration" @@ -741,6 +762,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -772,7 +796,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Disabling stops event ingestion and pauses the scheduled pull task; settings are kept so the integration can be enabled again.\n- Every call is recorded in the account audit log.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Write access also requires object permission: the account owner, an administrator, the creator, or a member of the assigned team; with no team, members with Integrations Manage may operate. Read-only integrations cannot be changed.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Disabling stops event ingestion and pauses the scheduled pull task; settings are kept so the integration can be enabled again.\n- Enabling an integration that is already enabled succeeds without change; the same holds for disabling a disabled one.\n- Every call is recorded in the account audit log.\n- These APIs manage public (account-level) integrations only, not channel-owned dedicated integrations.\n- Write access also requires object permission: the account owner, an administrator, the creator, or a member of the assigned team; with no team, members with Integrations Manage may operate. Read-only integrations cannot be changed.", "href": "/en/api-reference/on-call/integrations/integration-api-write-disable", "metadata": { "sidebarTitle": "Disable integration" @@ -811,6 +835,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -883,6 +910,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -914,7 +944,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- This is an irreversible bulk-delete operation.\n- High-risk operation. Console JWT callers must pass a second-factor code; `app_key` callers bypass the MFA prompt but remain audited — treat the key as a secret.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Permanently deletes every data row of the schema; the schema itself is kept.\n- The schema must exist and not be deleted; otherwise `InvalidParameter`.\n- Only an account admin, the schema creator, or a member of the schema's owning team may call this; others get `AccessDenied`.\n- Data writes to one schema (upsert, delete, truncate, CSV upload) run one at a time; a call made while another is running returns `RequestTooFrequently`.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-data-write-truncate", "metadata": { "sidebarTitle": "Truncate mapping data" @@ -953,6 +983,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -984,7 +1017,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Returns `null` if the API does not exist.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Returns `data: null` when no mapping API with this ID exists in the account.\n- A soft-deleted mapping API is still returned, with `status` = `deleted`.\n- There is no team check: any caller in the account can read any mapping API, including its `headers` in plain text.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-api-read-info", "metadata": { "sidebarTitle": "Get mapping API detail" @@ -1015,12 +1048,18 @@ "data": { "api_id": "665f1a2b3c4d5e6f7a8b9c02", "api_name": "CMDB API", + "description": "Query CMDB for host metadata", "url": "https://cmdb.example.com/api/lookup", + "headers": { + "X-Token": "example-token" + }, "timeout": 2, "retry_count": 1, "insecure_skip_verify": false, "status": "enabled", + "team_id": 0, "creator_id": 80011, + "updated_by": 80011, "created_at": 1710000000, "updated_at": 1710000000 } @@ -1034,6 +1073,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1065,7 +1107,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Poll until `status` is no longer `running`; `progress.completed_steps` out of `progress.total_steps` shows how far the job is.\n- Job state is kept for 24 hours after its last update; after that the call returns `ResourceNotFound`.\n- A `job_id` that belongs to another account returns `AccessDenied`.", "href": "/en/api-reference/on-call/status-pages/status-page-migration-status", "metadata": { "sidebarTitle": "Get migration status" @@ -1124,6 +1166,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1148,12 +1193,12 @@ "post": { "operationId": "channelEscalateRuleInfo", "summary": "Get escalation rule detail", - "description": "Retrieve detailed information for a specific escalation rule.", + "description": "Return one escalation rule of a channel, including its levels, time windows and filters.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Incidents Read** (`on-call`) or **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- A deleted rule is still returned, with `status` `deleted`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-info", "metadata": { "sidebarTitle": "Get escalation rule detail" @@ -1224,6 +1269,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1256,7 +1304,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- If `query` is provided, all source labels must be specified — partial source label queries are rejected.\n- Pagination uses cursor-based (`search_after_ctx`) or page-based (`p`, `limit`) navigation. `limit` defaults to 20, max 100.\n- The `search_after_ctx` token from a response can be passed back to retrieve the next page.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- The schema must exist and not be deleted; otherwise `InvalidParameter`.\n- `query` filters by exact source label values. Keys that are not source labels are dropped; if any key remains, every source label must be given, otherwise `InvalidParameter`.\n- Page-based navigation (`p`, `limit`) reaches at most 10,000 rows (`p * limit <= 10000`); go further with `search_after_ctx`.\n- `total` counts at most 1,000 matching rows; `used_cnt` is the schema's full row count.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-data-read-list", "metadata": { "sidebarTitle": "List mapping data" @@ -1287,7 +1335,7 @@ "data": { "items": [ { - "key": "server01", + "key": "02b8754747905747f7f76d802202d214", "fields": { "host": "server01", "owner": "alice", @@ -1299,7 +1347,8 @@ } ], "total": 1, - "has_next_page": false + "has_next_page": false, + "used_cnt": 1 } } } @@ -1311,6 +1360,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1341,12 +1393,12 @@ "post": { "operationId": "incidentPastList", "summary": "List past incidents", - "description": "List historical incidents related to the current incident for reference during triage.", + "description": "List closed incidents in the same channel that resemble a given incident, to reuse past root causes and resolutions.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **5 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Requires the Professional edition or higher; otherwise the call fails with `NoLicense`.\n- Candidates are closed incidents in the same channel that started within the 30 days before the reference incident started and whose semantic similarity exceeds the channel's similarity threshold.\n- Results list incidents with longer `root_cause` plus `resolution` text first, then higher `score`, then more recent `start_time`.\n- `limit` defaults to 5 when omitted or `0`.\n- An empty `items` array means no similar incident was found, or the reference incident has not been indexed for similarity search yet.\n- The reference incident must belong to a channel; otherwise the call fails with `InvalidParameter`.", "href": "/en/api-reference/on-call/incidents/incident-past-list", "metadata": { "sidebarTitle": "List past incidents" @@ -1387,6 +1439,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1414,12 +1469,12 @@ "post": { "operationId": "incidentSnooze", "summary": "Snooze incident", - "description": "Temporarily snooze notifications for an incident until a specified time.", + "description": "Pause notifications for acknowledged incidents for a given number of minutes.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only incidents in `Processing` progress can be snoozed; any other progress fails the whole call with `InvalidParameter`.\n- Notifications resume automatically after `minutes` elapse, or earlier through `POST /incident/wake`. The snooze end time is stored in the incident's `snoozed_before` (Unix seconds).\n- The snooze is also cleared when the incident is reassigned or returns to `Triggered`.", "href": "/en/api-reference/on-call/incidents/incident-snooze", "metadata": { "sidebarTitle": "Snooze incident" @@ -1458,6 +1513,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1487,12 +1545,12 @@ "post": { "operationId": "statusPageSubscriberExport", "summary": "Export subscribers", - "description": "Export subscribers list for a status page as a CSV attachment. The response is a `text/csv` file with columns: Method, Recipient, Components, Subscribe All, Locale.", + "description": "Export the subscribers of a status page as a CSV file.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |\n\n## Usage\n\n- Requires the On-call Standard plan or higher; other accounts get `AccessDenied`.\n- The response is a `text/csv` attachment, not a JSON envelope, with the columns Method, Recipient, Components, Subscribe All (`Yes`/`No`), and Locale.\n- Components lists component names joined by `, `; a component inside a section is written as `Section › Component`.\n- Public pages export email subscribers and internal pages export IM subscribers; filtering by `component_ids` also includes subscribers of all components.", "href": "/en/api-reference/on-call/status-pages/status-page-subscriber-export", "metadata": { "sidebarTitle": "Export subscribers" @@ -1516,6 +1574,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1542,12 +1603,12 @@ "post": { "operationId": "insightByTeam", "summary": "Get team insight", - "description": "Return insight metrics aggregated by team.", + "description": "Return incident and alert metrics grouped by team, one row per team per time bucket.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- One row per team per time bucket. Incidents without a team are aggregated into a row that has no `team_id`. `responder_ids` and `incident_ids` are ignored.\n- Incidents are counted by creation time. Rows are sorted by `ts` from newest to oldest, and a bucket (or dimension value) with no incidents produces no row — missing rows mean zero. `split_hours: true` returns up to three rows per bucket, one per `hours` value.\n- `total_alert_cnt`, `total_alert_event_cnt` and `noise_reduction_pct` honor only the time range, team, channel and severity filters; `query`, `labels`, `fields` and the duration filters apply to incident metrics only.\n- Members who are neither the account owner nor an admin only get data from channels they can access; other channels are silently excluded.\n- With `is_my_team: true`, `team_ids` is narrowed to the caller's teams; a caller who belongs to no team gets an empty result.", "href": "/en/api-reference/on-call/analytics/insight-by-team", "metadata": { "sidebarTitle": "Get team insight" @@ -1615,6 +1676,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1646,12 +1710,12 @@ "post": { "operationId": "insightChannelExport", "summary": "Export channel insight", - "description": "Export channel insight metrics as a CSV file — one row per channel (and per time/hour bucket when `aggregate_unit`/`split_hours` is used). The response is a CSV stream delivered with `Content-Disposition: attachment` — it is not a JSON envelope. `time_zone` defaults to UTC. Rows without a valid channel ID are skipped. Valid `export_fields` keys: channel_id, channel_name, total_incident_cnt, total_incidents_acknowledged, total_incidents_closed, total_incidents_auto_closed, total_incidents_manually_closed, total_incidents_timeout_closed, total_incidents_escalated, total_incidents_manually_escalated, total_incidents_timeout_escalated, total_incidents_reassigned, total_interruptions, total_notifications, total_engaged_seconds, mean_seconds_to_ack, mean_seconds_to_close, noise_reduction_pct, acknowledgement_pct, total_alert_cnt, total_alert_event_cnt, hours. The `hours` column is included by default only when `split_hours` is true. For compatibility, incident-export column keys are also accepted but produce empty columns.", + "description": "Export channel insight metrics as a CSV file with the same rows as `/insight/channel`.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- The response is a CSV file (`Content-Type: application/octet-stream`), not a JSON envelope. Validation errors are returned as JSON before any CSV bytes are written.\n- Takes the same filters as `/insight/channel`. Rows without a channel ID are skipped. The file has no time-bucket column, so with `aggregate_unit` the rows of different buckets cannot be told apart; export one bucket per request if you need the split.\n- `export_fields` sets the columns and their order: channel_id, channel_name, total_incident_cnt, total_incidents_acknowledged, total_incidents_closed, total_incidents_auto_closed, total_incidents_manually_closed, total_incidents_timeout_closed, total_incidents_escalated, total_incidents_manually_escalated, total_incidents_timeout_escalated, total_incidents_reassigned, total_interruptions, total_notifications, total_engaged_seconds, mean_seconds_to_ack, mean_seconds_to_close, noise_reduction_pct, acknowledgement_pct, total_alert_cnt, total_alert_event_cnt, hours. Unknown or duplicate keys are rejected. When it is omitted, all columns are exported, and `hours` is included only when `split_hours` is true.\n- The incident-snapshot keys (progress, assigned_to, raw_assigned_to, escalate_rule_name, responders, raw_responders, ackers, owner_id, owner_name, creator_id, creator_name, closer_id, closer_name, snooze_status, snoozed_before, ever_muted, frequency, is_rare, alert_cnt, active_alert_cnt, alert_event_cnt, description, labels, fields) are also accepted for compatibility and produce empty columns.\n- Column headers are localized (request locale, then the member's, then the account's). Time buckets follow `time_zone` (UTC when omitted).", "href": "/en/api-reference/on-call/analytics/insight-channel-export", "metadata": { "sidebarTitle": "Export channel insight" @@ -1665,7 +1729,7 @@ "schema": { "type": "string", "format": "binary", - "description": "CSV file stream (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename=channel_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers. Columns default to the full field set, or the keys given in `export_fields`." + "description": "CSV file (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename*=UTF-8''channel_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers." }, "example": "channel_id,channel_name,total_incident_cnt,total_incidents_closed\n4321322010131,Production Alerts,12,10\n" } @@ -1677,6 +1741,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1716,7 +1783,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Maximum 50 rules per pipeline.\n- Each rule has a `kind` (one of `title_reset`, `description_reset`, `severity_reset`, `alert_drop`, `alert_inhibit`), an optional `if` filter, and `settings` specific to the kind.\n- The `alert_inhibit` kind requires the Standard license or higher.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Replaces the integration's whole rule list with `rules`; an empty array removes every rule. At most 50 rules.\n- Rules run in array order on each incoming event of the integration before it becomes an alert; `alert_drop`, or an `alert_inhibit` that matches, discards the event and stops processing.\n- `integration_id` may be an account-level or a channel-owned integration; an ID not in the account returns `InvalidParameter`.\n- Write access also requires object permission: the account owner, an administrator, the integration creator, or a member of its team (for a channel-owned integration, a member of the channel's team); with no team, any caller with the API permission may write.\n- An `alert_inhibit` rule requires the Standard plan or higher; otherwise the call returns `NoLicense`.\n- On success the response carries only `request_id`; the `data` field is omitted.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alerts/alert-write-pipeline-upsert", "metadata": { "sidebarTitle": "Create or update alert pipeline" @@ -1743,8 +1810,7 @@ ] }, "example": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": null + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" } } } @@ -1755,6 +1821,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1810,7 +1879,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Returns every affected component, including hidden ones; component names, sections, and order reflect the page's current configuration.\n- Returns `ResourceNotFound` when the page or the event does not exist.", "href": "/en/api-reference/on-call/status-pages/status-page-change-info", "metadata": { "sidebarTitle": "Get status page event detail" @@ -1897,6 +1966,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -1932,12 +2004,12 @@ "post": { "operationId": "incidentResolve", "summary": "Resolve incident", - "description": "Mark an incident as resolved.", + "description": "Close one or more incidents, optionally recording root cause, resolution, and resolution form values.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- When a resolution form applies, `custom_fields`, `summary`, and `images` must match its visible elements and required rules.\n- For a batch, form values are accepted only when every selected incident resolves to the same form; otherwise resolve incidents individually.\n- The legacy `values` and `custom_values` properties are rejected; use `custom_fields`.\n- Audited — changes are recorded in the audit log.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- When a resolution form applies, `custom_fields`, `summary`, and `images` must match its visible elements and required rules.\n- For a batch, form values are accepted only when every selected incident resolves to the same form; otherwise resolve incidents individually.\n- The legacy `values` and `custom_values` properties are rejected; use `custom_fields`.\n- Incidents that are already closed are skipped without error; an unknown ID fails the whole call with `InvalidParameter`.\n- Resolving a `Triggered` incident first acknowledges it on behalf of the caller.\n- After closing, unfinished action items of the incident are converted to follow-ups, and later events no longer merge into the incident's existing alerts.\n- Returns `RequestTooFrequently` while another resolve, reopen, merge, comment, or delete is running in the same account; retry after a short delay.", "href": "/en/api-reference/on-call/incidents/incident-resolve", "metadata": { "sidebarTitle": "Resolve incident" @@ -1976,6 +2048,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2006,12 +2081,12 @@ "post": { "operationId": "incidentWarRoomList", "summary": "List war rooms", - "description": "List all war rooms associated with an incident.", + "description": "List the IM war room groups linked to an incident.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- War rooms whose IM integration is disabled or deleted are still returned, with `integration_unavailable` set to `true`.\n- Use `chat_id` and `integration_id` with `POST /incident/war-room/detail` to read the group's current name and join link.", "href": "/en/api-reference/on-call/incidents/incident-war-room-list", "metadata": { "sidebarTitle": "List war rooms" @@ -2040,7 +2115,19 @@ "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { - "items": [] + "items": [ + { + "account_id": 2451002751131, + "integration_id": 2490562293131, + "created_by": 2476444212131, + "chat_id": "oc_a0553eda9014c2de1b3a8f75b4e0c000", + "incident_id": "69da451ef77b1b51f40e83ee", + "status": "enabled", + "created_at": 1775972300, + "plugin_type": "feishu_app", + "chat_name": "Incident #0E83EE war room" + } + ] } } } @@ -2052,6 +2139,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2083,7 +2173,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- Both `start_time` and `end_time` are required Unix epoch seconds. Maximum span is 31 days.\n- Use `search_after_ctx` from the previous response to fetch the next page.\n- Results are filtered by the caller's channel data-access permissions.\n- Set `is_active` to `true` to retrieve only active (firing) alerts; `false` to retrieve resolved alerts.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Incidents Read** (`on-call`) or **Incidents Manage** (`on-call`) or **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- `start_time` and `end_time` are required Unix seconds and filter on the alert's `start_time`; the span must not exceed 31 days.\n- With `by_updated_at: true`, an `updated_at` window with the same bounds is added on top of the `start_time` filter, and the span must not exceed 7 days.\n- A `start_time` earlier than the account's data retention period is moved up to the retention start; an `end_time` before that start returns `InvalidParameter`.\n- Pass `search_after_ctx` from the previous response for the next page; without it, `p`/`limit` page numbers apply and `p * limit` must stay within 10,000.\n- `total` is capped at 1,000. In page-number mode `has_next_page` is computed from that capped total, so it turns `false` once you reach 1,000 alerts even when more match. Every non-empty page returns `search_after_ctx` for its last alert; to read past 1,000, pass it back and continue in cursor mode, where `has_next_page` is exact.\n- Results are filtered by the caller's channel data-access permissions.\n- Set `is_active` to `true` to retrieve only active (firing) alerts; `false` to retrieve resolved alerts.", "href": "/en/api-reference/on-call/alerts/alert-read-list", "metadata": { "sidebarTitle": "List alerts" @@ -2137,7 +2227,8 @@ "channel_name": "Production", "event_cnt": 3 } - ] + ], + "search_after_ctx": "663a1b2c3d4e5f6789abcdef" } } } @@ -2149,6 +2240,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2178,12 +2272,12 @@ "post": { "operationId": "statusPageChangeUpdate", "summary": "Update status page event", - "description": "Update an existing status page event.", + "description": "Update the title, responders, or linked events of a status page event.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- Status, description, and component impact cannot be changed here; post a timeline entry with `POST /status-page/change/timeline/create` instead.\n- An omitted or empty `responders` or `linked_changes` keeps the current list, so these lists cannot be cleared through this endpoint.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-change-update", "metadata": { "sidebarTitle": "Update status page event" @@ -2222,6 +2316,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2255,7 +2352,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |\n\n## Usage\n\n- Set `include_events=true` only when you need a preview of each alert's raw events.\n- Event previews are capped at the 20 newest events per alert. Use `POST /alert/event/list` for a full paginated event history.\n- `event_cnt` still reports the total number of raw events merged into each alert.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Set `include_events=true` only when you need a preview of each alert's raw events.\n- Event previews are capped at the 20 newest events per alert. Use `POST /alert/event/list` for a full paginated event history.\n- `event_cnt` still reports the total number of raw events merged into each alert.\n- `p` defaults to 1; `limit` omitted or `0` returns up to 1,000 alerts per page.", "href": "/en/api-reference/on-call/incidents/incident-alert-list", "metadata": { "sidebarTitle": "List alerts of incident" @@ -2351,6 +2448,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2381,12 +2481,12 @@ "post": { "operationId": "channelEscalateRuleUpdate", "summary": "Update escalation rule", - "description": "Update an existing escalation rule configuration.", + "description": "Replace the configuration of an existing escalation rule.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Full replacement: omitted `description`, `aggr_window`, `time_filters` and `filters` are reset to empty or `0`. Only `priority` keeps its current value when omitted.\n- Validation is the same as for create. The rule's `status` is not changed; use the enable and disable endpoints.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-update", "metadata": { "sidebarTitle": "Update escalation rule" @@ -2425,6 +2525,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2471,12 +2574,12 @@ "post": { "operationId": "calEventUpsert", "summary": "Upsert calendar event", - "description": "Create or update an event the calendar owns (a day off or a working-day override) over the days [start_at, end_at). Omit event_id to create a new event; a given event_id must be an existing event of this calendar. The write clears the calendar's other own events off the same days: an event fully inside the range is deleted, one partly inside is shortened, and one spanning the range is split in two, so the latest write decides those days. end_at must be later than start_at.", + "description": "Create or update one of a personal calendar's own events: a day off or a working-day override.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |\n\n## Usage\n\n- The event covers the days [`start_at`, `end_at`), dates in `YYYY-MM-DD`; `end_at` must be later than `start_at`.\n- Omit `event_id` to create an event; a given `event_id` must be an existing event of this calendar.\n- The write clears the calendar's other own events off the same days: an event fully inside the range is deleted, one partly inside is shortened, and one spanning the range is split in two, so the latest write decides those days.\n- Only personal calendars can be changed, and only by the account owner, an administrator, the calendar creator, or a member of the calendar's team; other callers get `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/calendars/cal-event-upsert", "metadata": { "sidebarTitle": "Upsert calendar event" @@ -2519,6 +2622,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2550,12 +2656,12 @@ "post": { "operationId": "statusPageChangeDelete", "summary": "Delete status page event", - "description": "Delete a status page event.", + "description": "Delete an incident or maintenance event from a status page.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- Deleting an event that does not exist returns success.\n- Subscriptions to this event are removed, and the scheduled transitions of an auto-updating maintenance are cancelled.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-change-delete", "metadata": { "sidebarTitle": "Delete status page event" @@ -2594,6 +2700,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2621,12 +2730,12 @@ "post": { "operationId": "incidentWarRoomDetail", "summary": "Get war room detail", - "description": "Retrieve the war room configuration and members for an incident.", + "description": "Fetch the current name and join link of a war room group from the IM platform.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** (`on-call`) |\n\n## Usage\n\n- Supported for Feishu, DingTalk, WeCom, and Slack IM integrations; other integrations fail with `InvalidParameter`.\n- If the IM platform lookup fails (for example, the group was dissolved outside Flashduty), the call still succeeds and every field is an empty string.", "href": "/en/api-reference/on-call/incidents/incident-war-room-detail", "metadata": { "sidebarTitle": "Get war room detail" @@ -2669,6 +2778,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2696,12 +2808,12 @@ "post": { "operationId": "calendarDelete", "summary": "Delete calendar", - "description": "Delete a personal service calendar. The call fails when referenced by escalation or silence rules.", + "description": "Delete a personal service calendar and its events when no rule references it.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |\n\n## Usage\n\n- If escalation rules or silence rules still use the calendar, the call returns HTTP 400 with `error.code` = `ReferenceExist` and `data.refs` listing them.\n- The calendar's own events are deleted together with it.\n- Only personal calendars can be changed, and only by the account owner, an administrator, the calendar creator, or a member of the calendar's team; other callers get `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/calendars/calendar-delete", "metadata": { "sidebarTitle": "Delete calendar" @@ -2740,6 +2852,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2771,7 +2886,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- Results are newest-first by default. Set `asc=true` to read events oldest-first.\n- Use `limit` with `search_after_ctx` from the previous response to fetch the next page.\n- Classic page-number pagination is also supported with `p`, but `p * limit` must stay within 10,000 records.\n- Each alert can accumulate a large raw event history; prefer cursor pagination for hot alerts.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Incidents Read** (`on-call`) or **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- Results are newest-first by default. Set `asc=true` to read events oldest-first.\n- Use `limit` with `search_after_ctx` from the previous response to fetch the next page.\n- Classic page-number pagination is also supported with `p`, but `p * limit` must stay within 10,000 records.\n- An `alert_id` not found in the account returns `InvalidParameter`.", "href": "/en/api-reference/on-call/alerts/alert-read-event-list", "metadata": { "sidebarTitle": "List events for an alert" @@ -2827,6 +2942,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2859,7 +2977,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- All alerts of the source incidents move to the target incident, and the target gains the sources' integrations.\n- Source incidents that are still open are closed. With `remove_source_incidents: true` they are then permanently deleted; otherwise they stay closed with an `i_merge` timeline entry that points to the target.\n- The target's progress, responders, and assignment do not change; `title`, when set, replaces the target's title.\n- Returns `RequestTooFrequently` while another resolve, reopen, merge, comment, or delete is running in the same account; retry after a short delay.", "href": "/en/api-reference/on-call/incidents/incident-merge", "metadata": { "sidebarTitle": "Merge incidents" @@ -2898,6 +3016,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -2934,7 +3055,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- `keys` are the row `key` values returned by `/enrichment/mapping/data/list` or `/enrichment/mapping/data/upsert`; keys that match no row are ignored.\n- The schema must exist and not be deleted; otherwise `InvalidParameter`.\n- Only an account admin, the schema creator, or a member of the schema's owning team may call this; others get `AccessDenied`.\n- Data writes to one schema (upsert, delete, truncate, CSV upload) run one at a time; a call made while another is running returns `RequestTooFrequently`.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-data-write-delete", "metadata": { "sidebarTitle": "Delete mapping data rows" @@ -2973,6 +3094,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3003,12 +3127,12 @@ "post": { "operationId": "incidentPostMortemDelete", "summary": "Delete post-mortem", - "description": "Delete a post-mortem report.", + "description": "Permanently delete a post-mortem report together with its uploaded media.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Requires the Professional edition or higher; otherwise the call fails with `NoLicense`.\n- The caller must be an account owner or admin, or a member of the post-mortem's team; otherwise the call fails with `AccessDenied`.\n- Linked incidents are unlinked, so their `post_mortem_id` becomes empty.\n- An unknown `post_mortem_id` returns `ResourceNotFound`.\n- On success the response has no `data` field.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/incidents/incident-post-mortem-delete", "metadata": { "sidebarTitle": "Delete post-mortem" @@ -3035,8 +3159,7 @@ ] }, "example": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": {} + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" } } } @@ -3047,6 +3170,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3073,12 +3199,12 @@ "post": { "operationId": "calendarUpdate", "summary": "Update calendar", - "description": "Update a personal service calendar. Only non-null fields are updated.", + "description": "Update a personal service calendar; only the fields you send are changed.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |\n\n## Usage\n\n- Send at least one field besides `cal_id`; otherwise the call returns `InvalidParameter`.\n- `workdays` and `extra_cal_ids` replace the stored lists when sent (an empty array clears them); `team_id: 0` removes the team.\n- `cal_name` must stay unique within the account.\n- Only personal calendars can be changed, and only by the account owner, an administrator, the calendar creator, or a member of the calendar's team; other callers get `AccessDenied`.\n- On success the response carries only `request_id`; the `data` field is omitted.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/calendars/calendar-update", "metadata": { "sidebarTitle": "Update calendar" @@ -3105,8 +3231,7 @@ ] }, "example": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": {} + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" } } } @@ -3117,6 +3242,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3152,12 +3280,12 @@ "post": { "operationId": "incidentWarRoomDelete", "summary": "Delete war room", - "description": "Delete an incident war room.", + "description": "Dissolve an incident's war room group on the IM platform and unlink it from the incident.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- The war room record is removed first; a failure to dissolve the group on the IM side (for example, it was already dissolved) is ignored.\n- Succeeds without changes when the incident has no war room on that integration.\n- To only unlink a war room whose IM integration is disabled or deleted, set `unlink_only: true` and pass its `chat_id`. This mode is limited to account owners and admins, fails with `InvalidParameter` while the integration is enabled, and does not dissolve the group.\n- On success the response has no `data` field.", "href": "/en/api-reference/on-call/incidents/incident-war-room-delete", "metadata": { "sidebarTitle": "Delete war room" @@ -3184,8 +3312,7 @@ ] }, "example": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": {} + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" } } } @@ -3196,6 +3323,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3223,12 +3353,12 @@ "post": { "operationId": "incidentRemove", "summary": "Delete an incident", - "description": "Permanently delete an incident and all associated data.", + "description": "Permanently delete incidents together with their alerts, raw events, and timelines.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Deletion cannot be undone. Analytics statistics of the deleted incidents are removed in the background.\n- Fails with `InvalidParameter` if any incident belongs to a channel the caller cannot access.\n- IDs that do not match an incident are ignored.\n- Returns `RequestTooFrequently` while another resolve, reopen, merge, comment, or delete is running in the same account; retry after a short delay.", "href": "/en/api-reference/on-call/incidents/incident-remove", "metadata": { "sidebarTitle": "Delete an incident" @@ -3267,6 +3397,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3295,12 +3428,12 @@ "post": { "operationId": "channelUnsubscribeRuleEnable", "summary": "Enable drop rule", - "description": "Enable a disabled drop rule. Only a `disabled` rule can be enabled.", + "description": "Enable a disabled drop rule so it discards matching alert events again.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Only a `disabled` rule can be enabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-unsubscribe-rule-enable", "metadata": { "sidebarTitle": "Enable drop rule" @@ -3339,6 +3472,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3371,7 +3507,7 @@ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- Sorted by incident creation time, newest first by default (`asc: true` for oldest first).\n- Page with `p` + `limit` (at most 10,000 records reachable) or, for deeper reads, pass the previous page's `search_after_ctx` back. When `search_after_ctx` is sent, `total` counts only the incidents after the cursor.\n- `responder_ids` keeps incidents in which any of the given members was a responder.\n- Members who are neither the account owner nor an admin only get data from channels they can access; other channels are silently excluded.\n- With `is_my_team: true`, `team_ids` is narrowed to the caller's teams; a caller who belongs to no team gets an empty result.", "href": "/en/api-reference/on-call/analytics/insight-incident-list", "metadata": { "sidebarTitle": "List insight incidents" @@ -3465,6 +3601,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3502,7 +3641,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- `status` and every component status in `updates` must be valid for `type`, and every `component_id` must exist on the page.\n- `updates` must be in non-decreasing `at_seconds` order. If `status` is `resolved` or `completed`, every affected component must end as `operational`.\n- With `notify_subscribers: true`, subscribers are notified once, about the last entry in `updates`.\n- For a maintenance with `auto_update_by_schedule: true`, the server moves it from `scheduled` to `ongoing` at `start_at_seconds` and from `ongoing` to `completed` at `close_at_seconds`, setting affected components back to `operational`.\n- Pass `draft_id` to publish a draft stored by `POST /status-page/draft/create`; the draft must target the same page and `type` and can be published only once.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-change-create", "metadata": { "sidebarTitle": "Create status page event" @@ -3544,6 +3683,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3593,7 +3735,7 @@ "On-call/Schedules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **60 requests/minute**; **10 requests/second** per account |\n| Permissions | **Schedules Read** (`on-call`) or **Schedules Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/minute**; **5 requests/second** per account |\n| Permissions | **Schedules Read** (`on-call`) or **Schedules Manage** (`on-call`) |\n\n## Usage\n\n- Nothing is saved. The body takes the same fields as `/schedule/create`, plus the required `start`/`end` window. `start` and `end` are 10-digit Unix timestamps in seconds; `end` must be after `start` and at most 45 days later.\n- Pass `time_zone` to preview in the time zone the schedule will be created with; without it, wall-clock values are evaluated in `Asia/Shanghai`.\n- Fields that only exist on saved schedules (`id`, `name`, `group_id`, `disabled`, `status`) are echoed from the request and are usually `null`.\n- `cur_oncall` is the shift in progress now and `next_oncall` the next shift with someone on duty; each is `null` when there is none within 45 days of now, independent of the requested window.", "href": "/en/api-reference/on-call/schedules/schedule-preview", "metadata": { "sidebarTitle": "Preview schedule" @@ -3626,6 +3768,7 @@ "name": null, "account_id": 0, "group_id": null, + "time_zone": "", "disabled": null, "create_at": 0, "create_by": 0, @@ -3794,6 +3937,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3873,7 +4019,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- `start_time` and `end_time` are Unix milliseconds.\n- Each record is one delivery of one event to one endpoint; `attempt` counts the HTTP tries, which are retried only on connection errors.\n- Stored request and response headers and bodies are truncated.\n- Pass `search_after_ctx` from the previous response for the next page; it is an empty string on the last page.\n- Returns `InvalidParameter` when delivery history recording is turned off for the deployment.", "href": "/en/api-reference/on-call/integrations/webhook-history-list", "metadata": { "sidebarTitle": "List webhook delivery history" @@ -3931,6 +4077,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -3961,12 +4110,12 @@ "post": { "operationId": "incidentWake", "summary": "Wake incident", - "description": "Cancel the snooze on an incident and resume notifications.", + "description": "End the snooze on incidents so that their notifications resume immediately.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Incidents whose snooze has already ended are skipped; a closed incident fails the whole call with `InvalidParameter`.", "href": "/en/api-reference/on-call/incidents/incident-wake", "metadata": { "sidebarTitle": "Wake incident" @@ -4005,6 +4154,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4033,12 +4185,12 @@ "post": { "operationId": "channelSilenceRuleEnable", "summary": "Enable silence rule", - "description": "Enable a disabled silence rule. Only a `disabled` rule can be enabled.", + "description": "Enable a disabled silence rule so it silences matching alert events again.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` rule can be enabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-silence-rule-enable", "metadata": { "sidebarTitle": "Enable silence rule" @@ -4077,6 +4229,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4104,12 +4259,12 @@ "post": { "operationId": "channelSilenceRuleUpdate", "summary": "Update silence rule", - "description": "Update an existing silence rule configuration.", + "description": "Replace the configuration of an existing silence rule.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- The same time window and `filters` requirements as create apply. Switching between `time_filter` and `time_filters` clears the other one.\n- `description`, `is_directly_discard` and `is_auto_delete` are always overwritten, so omitting them resets them to empty or `false`. `from_incident_id` cannot be changed.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-silence-rule-update", "metadata": { "sidebarTitle": "Update silence rule" @@ -4148,6 +4303,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4191,12 +4349,12 @@ "post": { "operationId": "incidentFeed", "summary": "Get incident timeline", - "description": "Retrieve the timeline feed for a specific incident, including state changes, comments and system events.", + "description": "List an incident's timeline entries, such as state changes, assignments, notifications, comments, and work item events.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |\n\n## Usage\n\n- For `i_comm` entries, `detail.comment_type` is resolved from the current account-level comment type definition at read time, so it reflects the type's latest name and color.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- For `i_comm` entries, `detail.comment_type` is resolved from the current account-level comment type definition at read time, so it reflects the type's latest name and color.\n- Only entries recorded on the incident itself are returned; alert-level entries are read through the alert endpoints.\n- Entries are ordered by creation time, newest first unless `asc` is `true`. Paginate with `p` and `limit`; `has_next_page` tells whether another page exists, and no total count is returned.\n- For `i_notify` entries, `failed_reason` is a localized message describing a delivery failure, filled in at read time.", "href": "/en/api-reference/on-call/incidents/incident-feed", "metadata": { "sidebarTitle": "Get incident timeline" @@ -4291,6 +4449,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4319,12 +4480,12 @@ "post": { "operationId": "channelInhibitRuleCreate", "summary": "Create inhibit rule", - "description": "Create an inhibit rule to suppress lower-priority alerts when higher-priority ones are firing.", + "description": "Create an inhibit rule that mutes alert events while a related source alert is still active.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Requires the Standard license or higher; otherwise the call returns `NoLicense`.\n- An incoming event is inhibited when it matches `target_filters` and the same channel has an active (not recovered) alert with a different `alert_key` that matches `source_filters`, started within the 10 minutes before the event, and has the same value for every key in `equals`.\n- The rule never fires when `equals` or `source_filters` is empty, or when the incoming event has no value for a label listed in `equals`.\n- Inhibit rules are checked after drop and silence rules; the first matching inhibit rule is applied.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-inhibit-rule-create", "metadata": { "sidebarTitle": "Create inhibit rule" @@ -4354,7 +4515,7 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "rule_id": "69db2f69a0fe7db6448b1504", - "rule_name": "Test inhibit rule" + "rule_name": "Suppress Info when Critical fires" } } } @@ -4366,6 +4527,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4421,12 +4585,12 @@ "post": { "operationId": "channelInhibitRuleEnable", "summary": "Enable inhibit rule", - "description": "Enable a disabled inhibit rule. Only a `disabled` rule can be enabled.", + "description": "Enable a disabled inhibit rule so it mutes matching alert events again.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Requires the Standard license or higher; otherwise the call returns `NoLicense`.\n- Only a `disabled` rule can be enabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-inhibit-rule-enable", "metadata": { "sidebarTitle": "Enable inhibit rule" @@ -4465,6 +4629,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4492,12 +4659,12 @@ "post": { "operationId": "mapping-schema-read-list", "summary": "List mapping schemas", - "description": "Return all mapping schemas for the account, sorted by creation time ascending.", + "description": "Return all mapping schemas of the account, newest first.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Returns every non-deleted schema of the account in one response, without pagination; `total` is the number of items.\n- Schemas of all teams are returned; there is no team filter.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-schema-read-list", "metadata": { "sidebarTitle": "List mapping schemas" @@ -4543,6 +4710,7 @@ "status": "enabled", "team_id": 0, "creator_id": 80011, + "updated_by": 80011, "created_at": 1710000000, "updated_at": 1710000000 } @@ -4558,6 +4726,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4582,12 +4753,12 @@ "post": { "operationId": "channelUnsubscribeRuleDelete", "summary": "Delete drop rule", - "description": "Delete a drop rule. Only a `disabled` rule can be deleted.", + "description": "Delete a disabled drop rule so it no longer appears in the channel's rule list.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Only a `disabled` rule can be deleted; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-unsubscribe-rule-delete", "metadata": { "sidebarTitle": "Delete drop rule" @@ -4626,6 +4797,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4658,7 +4832,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- Returns `null` data if no pipeline has been configured for the given integration.\n- Requires the caller to have access to the integration.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- When the integration has no pipeline, the response carries only `request_id` and the `data` field is omitted.\n- `integration_id` may be any account-level or channel-owned integration of the account; an unknown ID returns `InvalidParameter`.", "href": "/en/api-reference/on-call/alerts/alert-read-pipeline-info", "metadata": { "sidebarTitle": "Get alert pipeline" @@ -4728,6 +4902,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4754,12 +4931,12 @@ "post": { "operationId": "mapping-schema-write-delete", "summary": "Delete mapping schema", - "description": "Delete a mapping schema and all its associated data. Deletion is blocked if the schema is referenced by any enrichment rule or webhook.", + "description": "Delete a mapping schema and all of its data rows; refused while an enrichment rule or robot webhook uses it.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- If the schema is still referenced, the response returns HTTP 400 with a `refs` list of blocking references.\n- Only the schema creator, account admin, or team member can delete the schema.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.\n- High-risk operation. Console JWT callers must pass a second-factor code; `app_key` callers bypass the MFA prompt but remain audited — treat the key as a secret.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- The schema is soft-deleted (`status` becomes `deleted`) and all of its data rows are removed permanently.\n- If an integration's enrichment rule, or a Feishu, WeCom or Zoom robot webhook in an escalation rule, references the schema, the call returns HTTP 400 `ReferenceExist` with `data.refs` (each item has `kind` = `integration` or `escalate_rule`, `name`, `href`); at most 20 integrations are listed.\n- An unknown `schema_id` returns `InvalidParameter`.\n- Only an account admin, the schema creator, or a member of the schema's owning team may call this; others get `AccessDenied`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-schema-write-delete", "metadata": { "sidebarTitle": "Delete mapping schema" @@ -4798,6 +4975,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4824,12 +5004,12 @@ "post": { "operationId": "insightByAccount", "summary": "Get account-level insight", - "description": "Return aggregated incident insight metrics for the entire account.", + "description": "Return incident and alert metrics for the whole account, one row per time bucket.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- One row per time bucket for the whole account. `responder_ids` and `incident_ids` are ignored; use `/insight/responder` or `/insight/incident/list` for those.\n- Incidents are counted by creation time. Rows are sorted by `ts` from newest to oldest, and a bucket (or dimension value) with no incidents produces no row — missing rows mean zero. `split_hours: true` returns up to three rows per bucket, one per `hours` value.\n- `total_alert_cnt`, `total_alert_event_cnt` and `noise_reduction_pct` honor only the time range, team, channel and severity filters; `query`, `labels`, `fields` and the duration filters apply to incident metrics only.\n- Members who are neither the account owner nor an admin only get data from channels they can access; other channels are silently excluded.\n- With `is_my_team: true`, `team_ids` is narrowed to the caller's teams; a caller who belongs to no team gets an empty result.", "href": "/en/api-reference/on-call/analytics/insight-by-account", "metadata": { "sidebarTitle": "Get account-level insight" @@ -4895,6 +5075,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4927,12 +5110,12 @@ "post": { "operationId": "insightIncidentExport", "summary": "Export insight incidents", - "description": "Export the filtered incident analytics list as a CSV file. The response is a CSV stream delivered with `Content-Disposition: attachment` — it is not a JSON envelope. CSV headers and formatted values use the request locale, falling back to the member locale and then the account locale. `time_zone` defaults to the account time zone, then `Asia/Shanghai`. Export stops after at most 100,000 rows. Valid `export_fields` keys: incident_id, title, severity, progress, channel_id, channel_name, team_id, team_name, created_at, alert_cnt, active_alert_cnt, alert_event_cnt, seconds_to_ack, seconds_to_close, closed_by, owner_id, owner_name, creator_id, creator_name, closer_id, closer_name, engaged_seconds, hours, notifications, interruptions, acknowledgements, ackers, assignments, reassignments, escalations, manual_escalations, timeout_escalations, assigned_to, raw_assigned_to, escalate_rule_name, responders, raw_responders, snooze_status, snoozed_before, ever_muted, frequency, is_rare, description, labels, fields. When `export_fields` is omitted, all columns are exported.", + "description": "Export the incidents matched by the analytics filters as a CSV file, one row per incident.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- The response is a CSV file (`Content-Type: application/octet-stream`), not a JSON envelope. Validation errors are returned as JSON before any CSV bytes are written.\n- Takes the same filters and sort order as `/insight/incident/list`. Export stops once more than 100,000 rows have been written.\n- `start_time` is moved forward to the earliest date kept by the account's data retention; a range that ends before that date is rejected.\n- `export_fields` sets the columns and their order: incident_id, title, severity, progress, channel_id, channel_name, team_id, team_name, created_at, alert_cnt, active_alert_cnt, alert_event_cnt, seconds_to_ack, seconds_to_close, closed_by, owner_id, owner_name, creator_id, creator_name, closer_id, closer_name, engaged_seconds, hours, notifications, interruptions, acknowledgements, ackers, assignments, reassignments, escalations, manual_escalations, timeout_escalations, assigned_to, raw_assigned_to, escalate_rule_name, responders, raw_responders, snooze_status, snoozed_before, ever_muted, frequency, is_rare, description, labels, fields. Unknown or duplicate keys are rejected; when omitted, every column except the aliases `owner_id`, `creator_id`, `closer_id`, `snoozed_before` and `is_rare` is exported.\n- `description_html_to_text: true` strips HTML from the `description` column.\n- Headers and formatted values use the request locale, then the member's, then the account's. Times are rendered in `time_zone`, falling back to the account time zone and then `Asia/Shanghai`.", "href": "/en/api-reference/on-call/analytics/insight-incident-export", "metadata": { "sidebarTitle": "Export insight incidents" @@ -4946,7 +5129,7 @@ "schema": { "type": "string", "format": "binary", - "description": "CSV file stream (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename=incident_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers. Columns default to the full incident field set, or the keys given in `export_fields`." + "description": "CSV file (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename*=UTF-8''incident_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers." }, "example": "incident_id,title,severity,created_at\n6a86b5d6f72de50ae1ce2ffb,CPU usage above 90%,Critical,2026-01-01 10:00:00 +0800 CST\n" } @@ -4958,6 +5141,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -4997,12 +5183,12 @@ "post": { "operationId": "scheduleInfo", "summary": "Get schedule info", - "description": "Return details of an on-call schedule including the computed schedule layers for the requested time window (max 45 days).", + "description": "Return one on-call schedule with its layers and the shifts computed for a time window of up to 45 days.", "tags": [ "On-call/Schedules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Schedules Read** (`on-call`) or **Schedules Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Schedules Read** (`on-call`) or **Schedules Manage** (`on-call`) |\n\n## Usage\n\n- `start` and `end` are 10-digit Unix timestamps in seconds; `end` must be after `start` and at most 45 days later.\n- `schedule_layers` (and its alias `layer_schedules`) holds each visible layer's shifts in the window; `final_schedule` merges all layers, and a shift whose `group` is `null` is a gap with nobody on call.\n- The first computed shift may start before `start`: a shift already in progress at `start` is returned with its real start time.\n- `cur_oncall` is the shift in progress now and `next_oncall` the next shift with someone on duty; each is `null` when there is none within 45 days of now, independent of the requested window.\n- An unknown `schedule_id` returns `400`.", "href": "/en/api-reference/on-call/schedules/schedule-info", "metadata": { "sidebarTitle": "Get schedule info" @@ -5035,6 +5221,7 @@ "name": "test-000001", "account_id": 2451002751131, "group_id": 4291079133131, + "time_zone": "Asia/Shanghai", "disabled": 0, "create_at": 1766110836, "create_by": 2476123212131, @@ -5292,6 +5479,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5307,9 +5497,9 @@ "$ref": "#/components/schemas/ScheduleInfoRequest" }, "example": { - "schedule_id": 2001, - "start": 1712000000, - "end": 1712086400 + "schedule_id": 5789640530410, + "start": 1776009600, + "end": 1776268800 } } } @@ -5320,12 +5510,12 @@ "post": { "operationId": "template-write-update", "summary": "Update a template", - "description": "Update an existing template. Only the fields present in the request are written: a channel you omit keeps its current content, and an explicit empty string clears it.", + "description": "Update a notification template; only the fields present in the request are written.", "tags": [ "On-call/Notification templates" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Templates Manage** (`on-call`) |\n\n## Usage\n\n- Only the fields present in the request are written. A channel you omit keeps its current content; send it as an empty string to clear it.\n- The caller needs data-permission on the template's team; otherwise the response is `AccessDenied`.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Templates Manage** (`on-call`) |\n\n## Usage\n\n- `template_name` is required on every call and always written. Other fields left out keep their current values; a channel sent as an empty string is cleared, and notifications on that channel then use the built-in preset content.\n- Every non-empty channel source in the request is test-rendered against a mock incident; a template error fails the whole request with `InvalidParameter`. While `wecom_markdown_v2_enabled` is `true`, the rendered `wecom` content must be at most 4,096 bytes.\n- `incident_card_hidden_fields` and `incident_card_closed_action_apps`, when sent, replace the stored value as a whole.\n- An unknown `template_id` returns `InvalidParameter`; a new `template_name` must not be used by another template.\n- Only an account admin, the template creator, or a member of the template's owning team may call this; others get `AccessDenied`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/notification-templates/template-write-update", "metadata": { "sidebarTitle": "Update a template" @@ -5385,8 +5575,8 @@ "template_id": "6605a1b2c3d4e5f6a7b8c9d0", "template_name": "Prod incident default", "description": "Updated description.", - "email": "Incident {{ .IncidentName }} on {{ .Severity }}", - "sms": "[Flashduty] {{ .IncidentName }} — {{ .Severity }}" + "email": "Incident {{.Title}} is {{.IncidentSeverity}}", + "sms": "[Flashduty] {{.Title}} - {{.IncidentSeverity}}" } } } @@ -5397,12 +5587,12 @@ "post": { "operationId": "channelInfos", "summary": "Batch get channels", - "description": "Retrieve multiple channels by their IDs.", + "description": "Return the ID, name and status of up to 1,000 channels in one call.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- IDs that do not exist are skipped. Deleted channels are included, with `status` `deleted`.\n- Items are ordered by channel creation, not by the order of `channel_ids`.\n- Private channels are included regardless of the caller's team membership.", "href": "/en/api-reference/on-call/channels/channel-infos", "metadata": { "sidebarTitle": "Batch get channels" @@ -5449,6 +5639,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5478,12 +5671,12 @@ "post": { "operationId": "scheduleInfos", "summary": "Batch get schedules", - "description": "Return details of multiple on-call schedules by their IDs.", + "description": "Return the basic configuration of several on-call schedules by ID, without layers or computed shifts.", "tags": [ "On-call/Schedules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Schedules Read** (`on-call`) or **Schedules Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Schedules Read** (`on-call`) or **Schedules Manage** (`on-call`) |\n\n## Usage\n\n- Returns stored configuration only: `layers`, `schedule_layers`, `layer_schedules`, `cur_oncall` and `next_oncall` are always `null`, and `final_schedule` is empty. Use `/schedule/info` for layers and shifts.\n- IDs that do not exist are skipped without error; disabled schedules are included.", "href": "/en/api-reference/on-call/schedules/schedule-infos", "metadata": { "sidebarTitle": "Batch get schedules" @@ -5518,6 +5711,7 @@ "name": "test-000001", "account_id": 2451002751131, "group_id": 4291079133131, + "time_zone": "Asia/Shanghai", "disabled": 0, "create_at": 1766110836, "create_by": 2476123212131, @@ -5577,6 +5771,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5593,9 +5790,8 @@ }, "example": { "schedule_ids": [ - 2001, - 2002, - 2003 + 5789640530410, + 5432326025106 ] } } @@ -5612,7 +5808,7 @@ "On-call/Notification templates" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Templates Read** (`on-call`) |\n\n## Usage\n\n- Pass `000000000000000000000001` as `template_id` to retrieve the built-in preset template for the caller's account locale.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Templates Read** (`on-call`) or **Templates Manage** (`on-call`) |\n\n## Usage\n\n- Pass `6321aad26c12104586a88916` as `template_id` to get the built-in preset template: its channel contents are in the account language, its name and description in the caller's language.\n- An unknown `template_id` returns `InvalidParameter`. A soft-deleted template is still returned, with `status` = `deleted`.", "href": "/en/api-reference/on-call/notification-templates/template-read-info", "metadata": { "sidebarTitle": "Get template detail" @@ -5646,8 +5842,8 @@ "template_id": "6605a1b2c3d4e5f6a7b8c9d0", "template_name": "Prod incident default", "description": "Default template for production incidents.", - "email": "Incident {{ .IncidentName }} on {{ .Severity }}", - "sms": "[Flashduty] {{ .IncidentName }} — {{ .Severity }}", + "email": "Incident {{.Title}} is {{.IncidentSeverity}}", + "sms": "[Flashduty] {{.Title}} - {{.IncidentSeverity}}", "voice": "", "dingtalk": "", "wecom": "", @@ -5660,6 +5856,14 @@ "telegram": "", "slack": "", "zoom": "", + "wecom_markdown_v2_enabled": false, + "feishu_app_card_v2_table_enabled": false, + "feishu_app_card_v2_preserve_blank_lines": false, + "feishu_app_war_room_enabled": false, + "dingtalk_app_war_room_enabled": false, + "slack_app_war_room_enabled": false, + "incident_card_closed_action_apps": [], + "incident_card_hidden_fields": {}, "status": "enabled", "creator_id": 80011, "updated_by": 80011, @@ -5676,6 +5880,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5702,12 +5909,12 @@ "post": { "operationId": "channelEscalateRuleDisable", "summary": "Disable escalation rule", - "description": "Disable an escalation rule without deleting it. Only an `enabled` rule can be disabled.", + "description": "Disable an escalation rule without deleting it.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only an `enabled` rule can be disabled; any other status returns `InvalidParameter`.\n- A disabled rule takes no new incidents, and incidents already assigned through it stop receiving its notifications and escalations.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-disable", "metadata": { "sidebarTitle": "Disable escalation rule" @@ -5746,6 +5953,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5773,12 +5983,12 @@ "post": { "operationId": "incidentReset", "summary": "Update incident fields", - "description": "Update one or more editable fields of an incident in a single call, including title, description, impact, root cause, resolution, and severity. At least one field must be provided.", + "description": "Update an incident's title, description, impact, root cause, resolution, or severity in one call.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- At least one field must be provided. Omitted fields and empty strings keep their current values, so this endpoint cannot clear a field.\n- Values equal to the current ones are skipped. Each changed field adds its own timeline entry (`i_r_title`, `i_r_desc`, `i_r_impact`, `i_r_rc`, `i_r_rsltn`, or `i_r_severity`).\n- Changing `title`, `description`, or `incident_severity` adds that field to `manual_overrides`; after that, alerts merged into the incident no longer overwrite it.\n- Closed incidents can be updated as well.", "href": "/en/api-reference/on-call/incidents/incident-reset", "metadata": { "sidebarTitle": "Update incident fields" @@ -5817,6 +6027,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5845,12 +6058,12 @@ "post": { "operationId": "channelDisable", "summary": "Disable channel", - "description": "Disable a channel to stop incident routing without deleting it; a disabled channel discards incoming events. Only an `enabled` channel can be disabled.", + "description": "Disable a channel; while disabled it discards all incoming alert events.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only an `enabled` channel can be disabled; any other status returns `InvalidParameter`.\n- Rules and integrations are kept. Alert processing may take up to about one minute to see the new status.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-disable", "metadata": { "sidebarTitle": "Disable channel" @@ -5889,6 +6102,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -5920,7 +6136,7 @@ "On-call/Integrations" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Take `event_id` and `integration_id` from a record of `POST /webhook/history/list`; `event_id` starts with the delivery date (`YYYYMMDD`), which the lookup relies on.\n- When no record matches, `data` is an empty object.\n- Returns `InvalidParameter` when delivery history recording is turned off for the deployment.", "href": "/en/api-reference/on-call/integrations/webhook-history-detail", "metadata": { "sidebarTitle": "Get webhook delivery detail" @@ -5978,6 +6194,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6005,12 +6224,12 @@ "post": { "operationId": "scheduleList", "summary": "List schedules", - "description": "Return a paginated list of on-call schedules. When both start and end are provided (max 45 days apart), computed layer schedules are included.", + "description": "List on-call schedules with filters and pagination; pass `start` and `end` to also compute shifts.", "tags": [ "On-call/Schedules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Sorted by creation time, newest first. `query` matches the schedule name or description as a substring.\n- `is_my_team: true` keeps schedules owned by the caller's teams. `is_my_manage: true` keeps schedules owned by the caller's teams or created by the caller. The two cannot both be true. `team_ids` is intersected with either filter.\n- Without `start`/`end`, items carry stored configuration only (`layers`, `schedule_layers`, `cur_oncall`, `next_oncall` are `null`). With both set, `layers`, `schedule_layers`, `final_schedule`, `cur_oncall` and `next_oncall` are computed; `layer_schedules` stays `null` here.\n- `start` and `end` are 10-digit Unix timestamps in seconds; `end` must be after `start` and at most 45 days later. Sending `end` without `start` is rejected.", "href": "/en/api-reference/on-call/schedules/schedule-list", "metadata": { "sidebarTitle": "List schedules" @@ -6045,6 +6264,7 @@ "name": "test-000001", "account_id": 2451002751131, "group_id": 4291079133131, + "time_zone": "Asia/Shanghai", "disabled": 0, "create_at": 1766110836, "create_by": 2476123212131, @@ -6097,6 +6317,7 @@ "name": "test-2509300001", "account_id": 2451002751131, "group_id": 2477033058131, + "time_zone": "", "disabled": 0, "create_at": 1759132037, "create_by": 2476123212131, @@ -6141,6 +6362,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6170,12 +6394,12 @@ "post": { "operationId": "mapping-schema-write-create", "summary": "Create mapping schema", - "description": "Create a new mapping schema defining source lookup labels and the result labels to populate. Requires a Pro plan.", + "description": "Create a mapping schema that defines the lookup labels and the result labels to fill.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Schema names must be unique within an account.\n- `source_labels` (1–3 labels) are used as lookup keys; `result_labels` (1–10 labels) are the labels written on match.\n- Label names must match `^[a-zA-Z_][a-zA-Z0-9_]*$` and be unique within each list.\n- `source_labels` and `result_labels` must not overlap.\n- An account can have at most 20 mapping schemas.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Requires the Pro plan or higher; otherwise `NoLicense`.\n- `schema_name` must be unique among the account's non-deleted schemas.\n- `source_labels` (1–3) form the lookup key; `result_labels` (1–10) are written to alerts on a match. Label names must match `^[a-zA-Z_][a-zA-Z0-9_]*$`, be unique within each list, and not appear in both lists. Neither list can be changed later.\n- An account holds at most 20 non-deleted mapping schemas by default (some accounts have a higher limit); exceeding it returns `InvalidParameter`.\n- Concurrent create calls in one account return `RequestTooFrequently`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-schema-write-create", "metadata": { "sidebarTitle": "Create mapping schema" @@ -6217,6 +6441,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6257,7 +6484,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Only the API creator, account admin, or team member can update the API.\n- All updatable fields are optional — only provided fields are changed.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Fields left out keep their current values. `headers`, when sent, replaces the whole header map; send `{}` to remove all headers. `team_id` `0` removes the team.\n- The fields you send are validated as on create (`url` scheme and internal-address check, header rules, `timeout` 1–3, `retry_count` 0–1); `description` is cut to 500 characters.\n- An unknown `api_id` returns `InvalidParameter`; a new `api_name` must not be used by another mapping API.\n- Only an account admin, the mapping API creator, or a member of the mapping API's owning team may call this; others get `AccessDenied`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-api-write-update", "metadata": { "sidebarTitle": "Update mapping API" @@ -6296,6 +6523,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6329,7 +6559,7 @@ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Without `kind`, personal calendars are returned. `region.official.holiday` returns public holiday calendars, filtered to the caller's locale unless `no_locale` is `true`; use their `cal_id` in `extra_cal_ids`.\n- The list is not paginated; `total` equals the number of items.", "href": "/en/api-reference/on-call/calendars/calendar-list", "metadata": { "sidebarTitle": "List calendars" @@ -6412,6 +6642,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6438,12 +6671,12 @@ "post": { "operationId": "incidentResponderAdd", "summary": "Add incident responder", - "description": "Add a responder to an existing incident.", + "description": "Add members as responders to an open incident and notify them.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Existing responders are kept, and IDs that are already responders are skipped. To replace the responder set, use `POST /incident/assign`.\n- Closed incidents are rejected with `InvalidParameter`.\n- Member IDs that do not exist in the account are ignored.\n- New responders are notified according to `notify`; by default each follows their personal notification preference.", "href": "/en/api-reference/on-call/incidents/incident-responder-add", "metadata": { "sidebarTitle": "Add incident responder" @@ -6482,6 +6715,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6512,12 +6748,12 @@ "post": { "operationId": "insightTeamExport", "summary": "Export team insight", - "description": "Export team insight metrics as a CSV file — one row per team (and per time/hour bucket when `aggregate_unit`/`split_hours` is used). The response is a CSV stream delivered with `Content-Disposition: attachment` — it is not a JSON envelope. `time_zone` defaults to UTC. Rows without a valid team ID are skipped. Valid `export_fields` keys: team_id, team_name, total_incident_cnt, total_incidents_acknowledged, total_incidents_closed, total_incidents_auto_closed, total_incidents_manually_closed, total_incidents_timeout_closed, total_incidents_escalated, total_incidents_manually_escalated, total_incidents_timeout_escalated, total_incidents_reassigned, total_interruptions, total_notifications, total_engaged_seconds, mean_seconds_to_ack, mean_seconds_to_close, noise_reduction_pct, acknowledgement_pct, total_alert_cnt, total_alert_event_cnt, hours. The `hours` column is included by default only when `split_hours` is true. For compatibility, incident-export column keys are also accepted but produce empty columns.", + "description": "Export team insight metrics as a CSV file with the same rows as `/insight/team`.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- The response is a CSV file (`Content-Type: application/octet-stream`), not a JSON envelope. Validation errors are returned as JSON before any CSV bytes are written.\n- Takes the same filters as `/insight/team`. Rows without a team ID (incidents without a team) are skipped. The file has no time-bucket column, so with `aggregate_unit` the rows of different buckets cannot be told apart; export one bucket per request if you need the split.\n- `export_fields` sets the columns and their order: team_id, team_name, total_incident_cnt, total_incidents_acknowledged, total_incidents_closed, total_incidents_auto_closed, total_incidents_manually_closed, total_incidents_timeout_closed, total_incidents_escalated, total_incidents_manually_escalated, total_incidents_timeout_escalated, total_incidents_reassigned, total_interruptions, total_notifications, total_engaged_seconds, mean_seconds_to_ack, mean_seconds_to_close, noise_reduction_pct, acknowledgement_pct, total_alert_cnt, total_alert_event_cnt, hours. Unknown or duplicate keys are rejected. When it is omitted, all columns are exported, and `hours` is included only when `split_hours` is true.\n- The incident-snapshot keys (progress, assigned_to, raw_assigned_to, escalate_rule_name, responders, raw_responders, ackers, owner_id, owner_name, creator_id, creator_name, closer_id, closer_name, snooze_status, snoozed_before, ever_muted, frequency, is_rare, alert_cnt, active_alert_cnt, alert_event_cnt, description, labels, fields) are also accepted for compatibility and produce empty columns.\n- Column headers are localized (request locale, then the member's, then the account's). Time buckets follow `time_zone` (UTC when omitted).", "href": "/en/api-reference/on-call/analytics/insight-team-export", "metadata": { "sidebarTitle": "Export team insight" @@ -6531,7 +6767,7 @@ "schema": { "type": "string", "format": "binary", - "description": "CSV file stream (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename=team_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers. Columns default to the full field set, or the keys given in `export_fields`." + "description": "CSV file (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename*=UTF-8''team_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers." }, "example": "team_id,team_name,total_incident_cnt,total_incidents_closed\n4295771902131,SRE Team,12,10\n" } @@ -6543,6 +6779,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6577,12 +6816,12 @@ "post": { "operationId": "scheduleDelete", "summary": "Delete schedules", - "description": "Delete one or more on-call schedules by ID.", + "description": "Delete one or more on-call schedules by ID, together with their layers.", "tags": [ "On-call/Schedules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Schedules Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Schedules Manage** (`on-call`) |\n\n## Usage\n\n- A schedule still referenced by an escalation rule cannot be deleted: the call fails with HTTP 400 `ReferenceExist`, nothing is deleted, and `data.refs` lists the referencing rules (`kind`, `name`, `href`).\n- IDs that do not exist are ignored. The deletion of all listed schedules happens in one transaction.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/schedules/schedule-delete", "metadata": { "sidebarTitle": "Delete schedules" @@ -6621,6 +6860,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6637,7 +6879,7 @@ }, "example": { "schedule_ids": [ - 2001 + 5789640530410 ] } } @@ -6654,7 +6896,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- The latest timeline entry cannot be deleted; trying returns `InvalidParameter`.\n- After deletion, the event's status, description, close time, and affected components are recomputed from the remaining entries.\n- Returns success when the event does not exist, and `ResourceNotFound` when the event exists but `update_id` does not.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-change-timeline-delete", "metadata": { "sidebarTitle": "Delete event timeline entry" @@ -6693,6 +6935,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6721,12 +6966,12 @@ "post": { "operationId": "incidentWarRoomCreate", "summary": "Create war room", - "description": "Create a war room channel for collaborative incident response.", + "description": "Create an IM group chat as the war room for an incident and invite members into it.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Requires the Professional edition or higher; otherwise the call fails with `NoLicense`.\n- The IM integration must be enabled with war room turned on. Feishu, DingTalk, WeCom (self-built app only), and Slack are supported.\n- An incident can have only one war room. Calling again with the same `integration_id` returns the existing group (with an empty `share_link`); a different `integration_id` fails with `InvalidParameter`.\n- A concurrent creation for the same incident returns `RequestTooFrequently`.\n- A successful creation adds an `i_wr_create` timeline entry.", "href": "/en/api-reference/on-call/incidents/incident-war-room-create", "metadata": { "sidebarTitle": "Create war room" @@ -6769,6 +7014,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6797,12 +7045,12 @@ "post": { "operationId": "channelUnsubscribeRuleUpdate", "summary": "Update drop rule", - "description": "Update an existing drop rule configuration.", + "description": "Replace the name, description and conditions of an existing drop rule.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Full replacement: an omitted `description` becomes empty, and an omitted `filters` clears all conditions so the rule matches nothing.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-unsubscribe-rule-update", "metadata": { "sidebarTitle": "Update drop rule" @@ -6841,6 +7089,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6880,12 +7131,12 @@ "post": { "operationId": "routeUpsert", "summary": "Upsert routing rule", - "description": "Create or update routing rules for an integration to direct alerts to specific channels. At least one of `cases` or `default` must be provided.", + "description": "Create or replace the routing rule that sends a shared integration's alerts to channels.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- The whole rule is replaced: `cases`, `sections` or `default` missing from the request are removed. `version` increases on every call and the previous version is kept in the route history.\n- At least one of `cases` or `default` is required; a `default` with empty `channel_ids` counts as absent.\n- Only shared integrations have routing rules: a channel-exclusive or unknown `integration_id`, or a channel ID that does not exist, returns `InvalidParameter`.\n- When the integration belongs to a team, the caller must be the account owner or an admin, the integration's creator, or a member of that team; otherwise `AccessDenied`.\n- A successful response carries only `request_id`, with no `data` field.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/route-upsert", "metadata": { "sidebarTitle": "Upsert routing rule" @@ -6912,8 +7163,7 @@ ] }, "example": { - "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": {} + "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4" } } } @@ -6924,6 +7174,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -6973,12 +7226,12 @@ "post": { "operationId": "calendarCreate", "summary": "Create calendar", - "description": "Create a personal service calendar. Each account is limited to 5 calendars unless the Flashcat-Break-Cal-Limit header is set.", + "description": "Create a personal service calendar with its weekly workdays and linked holiday calendars.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |\n\n## Usage\n\n- A limit of 5 calendars is checked only when the caller is the account owner: once the account holds 5 calendars, the owner's create call returns `InvalidParameter`. Calls made by other members are not counted against this limit.\n- `cal_name` must be unique within the account, `timezone` must be a valid IANA name, and a nonzero `team_id` must be a team of the account; otherwise the call returns `InvalidParameter`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/calendars/calendar-create", "metadata": { "sidebarTitle": "Create calendar" @@ -7020,6 +7273,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7060,7 +7316,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- When an acknowledgement form applies, `custom_fields`, `summary`, and `images` must match its visible elements and required rules.\n- For a batch, form values are accepted only when every selected incident resolves to the same form; otherwise acknowledge incidents individually.\n- The legacy `values` and `custom_values` properties are rejected; use `custom_fields`.\n- Audited — changes are recorded in the audit log.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- When an acknowledgement form applies, `custom_fields`, `summary`, and `images` must match its visible elements and required rules.\n- For a batch, form values are accepted only when every selected incident resolves to the same form; otherwise acknowledge incidents individually.\n- The legacy `values` and `custom_values` properties are rejected; use `custom_fields`.\n- The calling member becomes a responder if not already one, and the incident moves to `Processing`. Acknowledging an incident you have already acknowledged changes nothing.\n- A closed incident or an unknown ID fails the whole call with `InvalidParameter`.", "href": "/en/api-reference/on-call/incidents/incident-ack", "metadata": { "sidebarTitle": "Acknowledge incident" @@ -7099,6 +7355,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7127,12 +7386,12 @@ "post": { "operationId": "channelEscalateRuleList", "summary": "List escalation rules", - "description": "List all escalation rules for a channel.", + "description": "List a channel's escalation rules in the order they are evaluated.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Incidents Read** (`on-call`) or **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- An unknown `channel_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-list", "metadata": { "sidebarTitle": "List escalation rules" @@ -7207,6 +7466,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7233,12 +7495,12 @@ "post": { "operationId": "channelCreate", "summary": "Create channel", - "description": "Create a new channel for incident management.", + "description": "Create a channel, optionally with a default escalation rule and channel-exclusive integrations.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- `channel_name` must be unique within the account; a duplicate returns `InvalidParameter`.\n- `group.method` `p` requires the Standard license or higher and `i` requires the Pro license. Creating a channel beyond the plan's channel quota also returns `NoLicense`.\n- When `escalate_rule` is set, an enabled escalation rule named `Default` is created with one level that notifies `escalate_rule.target` once.\n- Each ID in `plugin_ids` creates one channel-exclusive integration of that integration type, named after the type.\n- When `is_external_report_enabled` is `true`, the response also carries `external_report_token`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-create", "metadata": { "sidebarTitle": "Create channel" @@ -7268,7 +7530,7 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "channel_id": 6294542005131, - "channel_name": "API Test Channel" + "channel_name": "Production Alerts" } } } @@ -7280,6 +7542,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7300,6 +7565,11 @@ "description": "Handles all production environment alerts", "group": { "method": "p", + "equals": [ + [ + "labels.service" + ] + ], "time_window": 10, "window_type": "tumbling" }, @@ -7320,7 +7590,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Public pages list email subscribers and internal pages list IM subscribers.\n- Filtering by `component_ids` also returns subscribers who subscribed to all components.\n- Each item merges all subscriptions of one recipient; subscriptions to individual events are not shown.", "href": "/en/api-reference/on-call/status-pages/status-page-subscriber-list", "metadata": { "sidebarTitle": "List status page subscribers" @@ -7378,6 +7648,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7437,12 +7710,12 @@ "post": { "operationId": "incidentInfo", "summary": "Get incident detail", - "description": "Retrieve detailed information for a single incident including timeline, alerts, responders and custom fields.", + "description": "Get one incident by ID or short number, with responders, assignment, custom fields, and alert counts.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- `num` is not unique; when several incidents share it, the most recent one is returned. Prefer `incident_id`.\n- This endpoint does not fill `alerts` or the `account_*` fields. Use `POST /incident/alert/list` for alerts and `POST /incident/feed` for the timeline.\n- Image tokens starting with `img_` in `images` are replaced with download URLs.\n- An unknown incident returns `InvalidParameter`.", "href": "/en/api-reference/on-call/incidents/incident-info", "metadata": { "sidebarTitle": "Get incident detail" @@ -7508,6 +7781,7 @@ "snoozed_before": 0, "group_method": "n", "ever_muted": false, + "has_unfinished_work_item": false, "labels": { "check": "cpu_usage_high", "resource": "web-server-01", @@ -7559,6 +7833,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7590,7 +7867,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Returns `null` if the schema does not exist.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Returns `data: null` when no schema with this ID exists in the account.\n- A soft-deleted schema is still returned, with `status` = `deleted`.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-schema-read-info", "metadata": { "sidebarTitle": "Get mapping schema detail" @@ -7633,6 +7910,7 @@ "status": "enabled", "team_id": 0, "creator_id": 80011, + "updated_by": 80011, "created_at": 1710000000, "updated_at": 1710000000 } @@ -7646,6 +7924,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7672,12 +7953,12 @@ "post": { "operationId": "statusPageSubscriberImport", "summary": "Import subscribers", - "description": "Bulk import subscribers for a status page. The account must be allowlisted for subscriber import; otherwise the call is rejected with an access-denied error.", + "description": "Bulk import subscribers into a status page without sending confirmation emails.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **20 requests/minute**; **2 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **60 requests/minute**; **3 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |\n\n## Usage\n\n- Requires the On-call Professional plan, and the account must also be allowlisted for subscriber import; otherwise the call returns `AccessDenied`.\n- `method` must match the page: `email` for a public page with email subscription enabled, `im` for an internal page with IM subscription enabled.\n- Each imported recipient's existing subscriptions on this page are replaced by the imported ones.\n- Every `component_ids` and `change_ids` entry must exist on the page; one invalid ID rejects the whole request.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-subscriber-import", "metadata": { "sidebarTitle": "Import subscribers" @@ -7716,6 +7997,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7763,7 +8047,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- Both `start_time` and `end_time` are required Unix epoch seconds. `start_time` must be less than `end_time`; the span must not exceed 31 days.\n- Results are filtered by the caller's channel data-access permissions.\n- `severities` is a comma-separated string, e.g. `\"Critical,Warning\"`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Both `start_time` and `end_time` are required Unix epoch seconds. `start_time` must be less than `end_time`; the span must not exceed 31 days.\n- Results are filtered by the caller's channel data-access permissions.\n- `severities` is a comma-separated list matched against `event_severity`, e.g. `\"Critical,Warning\"`. Values are not validated, so an unknown value (or `Ok`) matches nothing.\n- Pass `search_after_ctx` from the previous response for the next page; without it, `p`/`limit` page numbers apply and `p * limit` must stay within 10,000.", "href": "/en/api-reference/on-call/alerts/alert-event-read-list", "metadata": { "sidebarTitle": "List raw alert events" @@ -7802,7 +8086,8 @@ "event_severity": "Critical", "event_time": 1712650000 } - ] + ], + "search_after_ctx": "663a1b2c3d4e5f6789abc001" } } } @@ -7814,6 +8099,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7843,12 +8131,12 @@ "post": { "operationId": "calEventDelete", "summary": "Delete calendar event", - "description": "Delete one event of a personal calendar by event_id, or clear the calendar's own events off the days [start_at, end_at). Pass either event_id or both start_at and end_at. Cleared days fall back to the linked holiday calendars and the weekly workdays.", + "description": "Delete one personal-calendar event by ID, or clear the calendar's own events from a date range.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Calendars Manage** (`on-call`) |\n\n## Usage\n\n- Pass either `event_id`, or both `start_at` and `end_at` (dates in `YYYY-MM-DD`, covering [`start_at`, `end_at`)); any other combination returns `InvalidParameter`.\n- Cleared days fall back to the linked holiday calendars and the weekly workdays.\n- Only personal calendars can be changed, and only by the account owner, an administrator, the calendar creator, or a member of the calendar's team; other callers get `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/calendars/cal-event-delete", "metadata": { "sidebarTitle": "Delete calendar event" @@ -7887,6 +8175,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -7919,7 +8210,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) |\n\n## Usage\n\n- All `integration_ids` must be accessible to the caller.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Every `integration_ids` entry must be an integration of the account; one unknown ID fails the whole request with `InvalidParameter`.\n- `items` holds one entry per integration that has a pipeline; integrations without one are absent.", "href": "/en/api-reference/on-call/alerts/alert-read-pipeline-list", "metadata": { "sidebarTitle": "List alert pipelines" @@ -7965,11 +8256,11 @@ ], "settings": { "equals": [ - "service" + "labels.service" ], "source_filters": [ { - "key": "alert_severity", + "key": "severity", "oper": "IN", "vals": [ "Critical" @@ -7997,6 +8288,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8026,12 +8320,12 @@ "get": { "operationId": "incidentPostMortemInfo", "summary": "Get post-mortem", - "description": "Retrieve a post-mortem report by its `post_mortem_id`. List reports via `/incident/post-mortem/list` first — each row carries the incident it covers — then fetch the full report here by that id.", + "description": "Get the full content and auto-aggregated basics of a post-mortem report by its ID.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Get `post_mortem_id` from `POST /incident/post-mortem/list`, or from an incident's `post_mortem_id`.\n- Private post-mortems can be read only by account owners, admins, and members of the post-mortem's team; others get `AccessDenied`.\n- An unknown `post_mortem_id` returns `ResourceNotFound`.", "href": "/en/api-reference/on-call/incidents/incident-post-mortem-info", "metadata": { "sidebarTitle": "Get post-mortem" @@ -8076,6 +8370,8 @@ "team_id": 2477033058131, "channel_id": 3047621227131, "is_private": false, + "generation": 0, + "revision": 12, "channel_name": "Ops Channel", "created_at_seconds": 1773900354, "updated_at_seconds": 1773909012 @@ -8096,7 +8392,8 @@ "content": { "content": "{\"type\":\"doc\",\"content\":[]}" }, - "follow_ups": "" + "follow_ups": "", + "has_active_incident": false } } } @@ -8108,6 +8405,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8123,7 +8423,7 @@ "schema": { "type": "string" }, - "description": "Post-mortem ID. Deterministic hash derived from account ID and the set of linked incident IDs." + "description": "Post-mortem ID: a 32-character hex string derived from the account ID and the linked incident IDs." } ] } @@ -8132,12 +8432,12 @@ "post": { "operationId": "calEventList", "summary": "List calendar events", - "description": "Return events for a personal calendar within a year/month/day scope. When month and day are both omitted the whole year is returned. The response also carries days, the resolved state of every day in the scope.", + "description": "Return a personal calendar's events for a year, month or day, plus the resolved state of each day.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- `year` defaults to the current year; without `month` the whole year is returned, and `day` requires `month`.\n- `items` merges the calendar's own events (`cale.*` IDs), one generated `non_work.YYYYMMDD` entry per non-working weekday when `workdays` is set, and the events of the linked holiday calendars; `total` counts all of them.\n- `days` gives the resolved state of every day in the scope.\n- Only personal calendars (`cal_id` starting with `cal.`) are supported; other IDs return `InvalidParameter`.", "href": "/en/api-reference/on-call/calendars/cal-event-list", "metadata": { "sidebarTitle": "List calendar events" @@ -8226,6 +8526,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8259,7 +8562,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- `at_seconds` must not be earlier than the event's latest timeline entry.\n- Component changes whose status equals the component's current status are dropped from the stored entry.\n- Moving to `resolved` or `completed` requires every affected component to be `operational`; posting a non-terminal status on a closed event reopens it.\n- The event description is set to this entry's description. If the event has `notify_subscribers` enabled, subscribers are notified about this entry.\n- Manually moving an auto-updating maintenance to `ongoing` or `completed` cancels the matching scheduled transition.\n- Pass `draft_id` to publish a stored draft whose `change_id` is this event; a draft can be published only once.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-change-timeline-create", "metadata": { "sidebarTitle": "Create event timeline entry" @@ -8300,6 +8603,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8336,12 +8642,12 @@ "post": { "operationId": "incidentDisableMerge", "summary": "Disable incident merge", - "description": "Disable automatic merging for a specific incident.", + "description": "Stop new alerts and events from being merged into the given incidents.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Later events no longer merge into the incidents' existing alerts, and alert grouping no longer adds new alerts to these incidents.\n- IDs that do not match an incident are ignored.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/incidents/incident-disable-merge", "metadata": { "sidebarTitle": "Disable incident merge" @@ -8380,6 +8686,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8408,12 +8717,12 @@ "post": { "operationId": "statusPageMigrationCancel", "summary": "Cancel status page migration", - "description": "Cancel an in-progress status page migration job. Only jobs currently in the `running` state can be cancelled.", + "description": "Cancel a running Atlassian Statuspage migration job.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Only a job whose `status` is `running` can be cancelled; otherwise the call returns `InvalidParameter`.\n- The job is marked `cancelled` at once and the account can start a new migration; data already imported is kept.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-migration-cancel", "metadata": { "sidebarTitle": "Cancel status page migration" @@ -8452,6 +8761,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8478,12 +8790,12 @@ "post": { "operationId": "enrichment-write-upsert", "summary": "Upsert enrichment rules", - "description": "Create or fully replace the enrichment rule set for an integration. The entire `rules` array is replaced atomically.", + "description": "Create or replace the whole enrichment rule set of an integration.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Enrichment rules are evaluated in order.\n- Each rule has a `kind`: `extraction` (regex/gjson extraction), `composition` (template-based label composition), `mapping` (lookup via mapping schema or API), or `drop` (remove labels).\n- The optional `if` field is an `AndFilters` condition: if it does not match, the rule is skipped.\n- For `kind: extraction`: `source_field` must be `title`, `description`, or a `labels.*` key; specify exactly one of `pattern` (RE2 regex — its capture groups are joined with a space and written to `result_label`) or `g_json` (GJson path).\n- For `kind: composition`: `template` is a Go text/template rendered against the event struct, e.g. `{{.Title}}`, `{{.Description}}`, `{{.Labels.key}}`.\n- For `kind: mapping`: `mapping_type` is `schema` (default) or `api`; provide `schema_id` or `api_id` accordingly.\n- For `kind: drop`: `drop_labels` lists the label keys to remove.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- `rules` replaces the stored rule set as a whole; send `[]` to remove all rules.\n- The integration must exist (`InvalidParameter` otherwise) and the caller must be allowed to edit it: an account admin, the integration's creator, someone who can edit its channel (for an integration inside a channel), or a member of its owning team. Integrations with no team and no channel can be edited by any member. Others get `AccessDenied`.\n- Rules run in array order on every incoming alert and change event, and each rule sees the labels written by the rules before it. A rule whose `if` conditions do not all match is skipped; a rule that fails at run time (no regex match, lookup miss, API error) is skipped without affecting the event.\n- Condition keys in `if` must be alert or change event keys (for example `title`, `description`, `labels.`); other keys return `InvalidParameter`.\n- `schema_id` and `api_id` are not checked on save; a rule pointing at a missing or deleted schema or API does nothing at run time. `mapping` rules with `mapping_type` = `api` run for alert events only.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alert-enrichment/enrichment-write-upsert", "metadata": { "sidebarTitle": "Upsert enrichment rules" @@ -8522,6 +8834,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8567,12 +8882,12 @@ "post": { "operationId": "alert-read-list-by-ids", "summary": "List alerts by IDs", - "description": "Return the details of multiple alerts by their IDs in a single request. Note: this endpoint does not paginate — `total` and `has_next_page` are always `0`/`false` and `search_after_ctx` is never set.", + "description": "Return the details of several alerts by ID in one request, without pagination.", "tags": [ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- All provided `alert_ids` must belong to the caller's account; any invalid ID causes the entire request to fail.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Incidents Read** (`on-call`) or **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- A malformed ID fails the request with `InvalidParameter`; well-formed IDs not found in the account are left out of `items`.\n- The response is not paginated: `total` is always `0`, `has_next_page` is always `false`, and `search_after_ctx` is omitted.", "href": "/en/api-reference/on-call/alerts/alert-read-list-by-ids", "metadata": { "sidebarTitle": "List alerts by IDs" @@ -8620,6 +8935,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8648,12 +8966,12 @@ "post": { "operationId": "channelEscalateRuleEnable", "summary": "Enable escalation rule", - "description": "Enable a disabled escalation rule. Only a `disabled` rule can be enabled.", + "description": "Enable a disabled escalation rule so it can take new incidents again.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` rule can be enabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-enable", "metadata": { "sidebarTitle": "Enable escalation rule" @@ -8692,6 +9010,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8724,7 +9045,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** or **Templates Read** or **Templates Manage** (`on-call`) |\n\n## Usage\n\n- Only incidents in channels the caller can access are returned.\n- `start_time` and `end_time` filter on incident start time and may span at most 31 days. A `start_time` earlier than the account's data retention period is moved up to the retention boundary; an `end_time` before that boundary fails with `InvalidParameter`.\n- Results are sorted by `start_time`, newest first unless `asc` is `true`.\n- Paginate with `p` and `limit`, or pass the previous response's `search_after_ctx`, in which case `p` is ignored.\n- `total` is capped at 1,000. With `p`/`limit` paging, `has_next_page` turns `false` once `p` × `limit` reaches 1,000 even if more incidents match. To read further, pass the `search_after_ctx` returned with every non-empty page; in cursor mode `has_next_page` reflects whether more rows really exist.\n- Without `progress`, incidents in every progress state are returned.", "href": "/en/api-reference/on-call/incidents/incident-list", "metadata": { "sidebarTitle": "List incidents" @@ -8795,6 +9116,7 @@ "snoozed_before": 0, "group_method": "n", "ever_muted": false, + "has_unfinished_work_item": false, "labels": { "check": "cpu_usage_high", "resource": "web-server-01", @@ -8848,6 +9170,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8887,7 +9212,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |\n\n## Usage\n\n- Use this endpoint to inspect synchronization mappings between ServiceDeskPlus requests and Flashduty incidents, including the external request link and sync status.\n- When `incident_id` is not provided, `start_time` and `end_time` are required Unix-second timestamps; the time window cannot exceed 30 days.\n- `status` accepts only `success` and `failed`, representing successful and failed synchronization records.\n- Results are sorted by the internal record ID. Set `asc` to `true` for ascending order; otherwise records are returned descending. Pass the returned `search_after_ctx` to continue pagination.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Use this endpoint to inspect synchronization mappings between ServiceDeskPlus requests and Flashduty incidents, including the external request link and sync status.\n- When `incident_id` is not provided, `start_time` and `end_time` are required Unix-second timestamps; the time window cannot exceed 30 days.\n- `status` accepts only `success` and `failed`, representing successful and failed synchronization records.\n- Results are sorted by the internal record ID. Set `asc` to `true` for ascending order; otherwise records are returned descending.\n- Pagination uses only `search_after_ctx`: pass the value returned by the previous response; `p` is ignored.", "href": "/en/api-reference/on-call/incidents/incident-service-desk-plus-request-read-list", "metadata": { "sidebarTitle": "Get ServiceDeskPlus linked incidents" @@ -8943,6 +9268,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -8980,7 +9308,7 @@ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- Only the time range, `team_ids`, `channel_ids`, `severities`, `is_my_team` and `split_hours` filter the result; other filter fields and `aggregate_unit` are ignored.\n- Alerts are counted in hourly buckets, so the effective range is aligned to whole hours.\n- With `split_hours: true`, the top `k` is computed separately for each of `work`, `sleep` and `off`, so up to 3 × `k` rows come back.\n- Members who are neither the account owner nor an admin only get data from channels they can access; other channels are silently excluded.", "href": "/en/api-reference/on-call/analytics/insight-topk-alerts-by-label", "metadata": { "sidebarTitle": "Get top-K alerts grouped by check or resource" @@ -9037,6 +9365,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9072,7 +9403,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Every ID must be an existing integration of the account; otherwise `InvalidParameter`.\n- Integrations that have no rule set are left out of `items`.", "href": "/en/api-reference/on-call/alert-enrichment/enrichment-read-list", "metadata": { "sidebarTitle": "List enrichment rules" @@ -9123,6 +9454,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9152,12 +9486,12 @@ "post": { "operationId": "channelSilenceRuleDisable", "summary": "Disable silence rule", - "description": "Disable a silence rule without deleting it. Only an `enabled` rule can be disabled.", + "description": "Disable a silence rule without deleting it.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only an `enabled` rule can be disabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-silence-rule-disable", "metadata": { "sidebarTitle": "Disable silence rule" @@ -9196,6 +9530,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9228,7 +9565,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- The integration must be an enabled custom action integration whose channels include the incident's channel; otherwise the call fails with `InvalidParameter`.\n- The server posts the incident payload to the action's URL with a 2-second timeout. If that request fails, the call still returns HTTP 200 with the error in `data.message`; on success `data` is `null`.\n- A successful run adds an `i_custom` timeline entry.", "href": "/en/api-reference/on-call/incidents/incident-custom-action-do", "metadata": { "sidebarTitle": "Execute custom action" @@ -9256,9 +9593,7 @@ }, "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", - "data": { - "message": "" - } + "data": null } } } @@ -9269,6 +9604,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9301,7 +9639,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- Use `p` (page number, starting at 1) and `limit` (max 100, default 20) for pagination.\n- Set `asc` to `true` for chronological order.\n- Use `types` to filter by specific feed types (e.g. `a_comm`, `a_merge`).", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Use `p` (page number, starting at 1) and `limit` (max 100, default 20) for pagination.\n- Set `asc` to `true` for chronological order.\n- Use `types` to filter by specific feed types (e.g. `a_comm`, `a_merge`).\n- An `alert_id` not found in the account returns `InvalidParameter`.", "href": "/en/api-reference/on-call/alerts/alert-read-feed", "metadata": { "sidebarTitle": "List alert activity feed" @@ -9338,8 +9676,10 @@ "detail": { "comment": "Investigating now." }, + "account_id": 10023, "creator_id": 80011, - "created_at": 1712651000 + "created_at": 1712651000000, + "updated_at": 1712651000000 } ] } @@ -9353,6 +9693,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9381,12 +9724,12 @@ "post": { "operationId": "insightResponderExport", "summary": "Export responder insight", - "description": "Export responder insight metrics as a CSV file — one row per responder (and per time/hour bucket when `aggregate_unit`/`split_hours` is used). The response is a CSV stream delivered with `Content-Disposition: attachment` — it is not a JSON envelope. `time_zone` defaults to UTC. Rows without a valid responder ID are skipped. Valid `export_fields` keys: responder_id, responder_name, total_incident_cnt, total_incidents_acknowledged, total_incidents_reassigned, total_incidents_escalated, total_incidents_manually_escalated, total_incidents_timeout_escalated, total_interruptions, total_notifications, total_engaged_seconds, mean_seconds_to_ack, acknowledgement_pct, hours. The `hours` column is included by default only when `split_hours` is true. For compatibility, incident-export column keys are also accepted but produce empty columns.", + "description": "Export responder insight metrics as a CSV file with the same rows as `/insight/responder`.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **100 requests/day**; **20 requests/minute**; **10 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- The response is a CSV file (`Content-Type: application/octet-stream`), not a JSON envelope. Validation errors are returned as JSON before any CSV bytes are written.\n- Takes the same filters as `/insight/responder`. Rows without a responder ID are skipped. The file has no time-bucket column, so with `aggregate_unit` the rows of different buckets cannot be told apart; export one bucket per request if you need the split.\n- `export_fields` sets the columns and their order: responder_id, responder_name, total_incident_cnt, total_incidents_acknowledged, total_incidents_reassigned, total_incidents_escalated, total_incidents_manually_escalated, total_incidents_timeout_escalated, total_interruptions, total_notifications, total_engaged_seconds, mean_seconds_to_ack, acknowledgement_pct, hours. Unknown or duplicate keys are rejected. When it is omitted, all columns are exported, and `hours` is included only when `split_hours` is true.\n- The incident-snapshot keys (progress, assigned_to, raw_assigned_to, escalate_rule_name, responders, raw_responders, ackers, owner_id, owner_name, creator_id, creator_name, closer_id, closer_name, snooze_status, snoozed_before, ever_muted, frequency, is_rare, alert_cnt, active_alert_cnt, alert_event_cnt, description, labels, fields) are also accepted for compatibility and produce empty columns.\n- Column headers are localized (request locale, then the member's, then the account's). Time buckets follow `time_zone` (UTC when omitted).", "href": "/en/api-reference/on-call/analytics/insight-responder-export", "metadata": { "sidebarTitle": "Export responder insight" @@ -9400,7 +9743,7 @@ "schema": { "type": "string", "format": "binary", - "description": "CSV file stream (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename=responder_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers. Columns default to the full field set, or the keys given in `export_fields`." + "description": "CSV file (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename*=UTF-8''responder_export_yyyyMMdd_HHmmss.csv`). The first row holds localized column headers." }, "example": "responder_id,responder_name,total_incident_cnt,total_incidents_acknowledged\n3790925372131,alice,5,4\n" } @@ -9412,6 +9755,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9451,7 +9797,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** or **Incidents Manage** or **Channels Read** (`on-call`) |\n\n## Usage\n\n- IDs that do not match an incident are omitted; `total` is the number of incidents found and `has_next_page` is always `false`.\n- Results are sorted by `start_time`, newest first.\n- This endpoint does not fill `integration_type` or `assigned_to.escalate_rule_name`.", "href": "/en/api-reference/on-call/incidents/incident-list-by-ids", "metadata": { "sidebarTitle": "List incidents by IDs" @@ -9480,7 +9826,7 @@ "example": { "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { - "total": 2, + "total": 1, "has_next_page": false, "items": [ { @@ -9521,6 +9867,7 @@ "snoozed_before": 0, "group_method": "n", "ever_muted": false, + "has_unfinished_work_item": false, "labels": {}, "fields": {}, "assigned_to": { @@ -9559,6 +9906,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9588,12 +9938,12 @@ "post": { "operationId": "incidentPostMortemList", "summary": "List post-mortems", - "description": "List post-mortem reports with optional filters.", + "description": "List post-mortem reports, optionally filtered by status, team, channel, and creation time.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Account owners and admins see all post-mortems; other members see public ones plus private ones that belong to their own teams.\n- Results are sorted by `order_by` (default `created_at_seconds`), descending unless `asc` is `true`.\n- Items carry metadata only; fetch the full report with `GET /incident/post-mortem/info`.", "href": "/en/api-reference/on-call/incidents/incident-post-mortem-list", "metadata": { "sidebarTitle": "List post-mortems" @@ -9641,6 +9991,8 @@ "team_id": 2477033058131, "channel_id": 3047621227131, "is_private": false, + "generation": 0, + "revision": 12, "channel_name": "Ops Channel", "created_at_seconds": 1773900354, "updated_at_seconds": 1773909012 @@ -9657,6 +10009,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9685,12 +10040,12 @@ "post": { "operationId": "mapping-api-read-list", "summary": "List mapping APIs", - "description": "Return all mapping APIs configured for the account.", + "description": "Return all mapping APIs of the account, newest first.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Returns every non-deleted mapping API in one response, without pagination; `total` is the number of items.\n- Mapping APIs of all teams are returned, with their `headers` in plain text.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-api-read-list", "metadata": { "sidebarTitle": "List mapping APIs" @@ -9727,7 +10082,7 @@ "description": "Query CMDB for host metadata", "url": "https://cmdb.example.com/api/lookup", "headers": { - "Authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.example-token" + "X-Token": "example-token" }, "timeout": 2, "retry_count": 1, @@ -9735,6 +10090,7 @@ "status": "enabled", "team_id": 0, "creator_id": 80011, + "updated_by": 80011, "created_at": 1710000000, "updated_at": 1710000000 } @@ -9750,6 +10106,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9774,12 +10133,12 @@ "post": { "operationId": "incidentUnack", "summary": "Unacknowledge incident", - "description": "Remove the acknowledge status from an incident.", + "description": "Withdraw the calling member's acknowledgement of one or more incidents.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only the calling member's acknowledgement is removed. The incident returns to `Triggered`, and any snooze is cleared, only when no other responder still has it acknowledged.\n- Every incident must be in `Processing`; a `Triggered` or `Closed` incident fails the whole call with `InvalidParameter`.", "href": "/en/api-reference/on-call/incidents/incident-unack", "metadata": { "sidebarTitle": "Unacknowledge incident" @@ -9818,6 +10177,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9851,7 +10213,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Only the schema creator, account admin, or team member can update the schema.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Fields left out keep their current values; `team_id` `0` removes the team.\n- An unknown `schema_id` returns `InvalidParameter`; a new `schema_name` must not be used by another schema.\n- Only an account admin, the schema creator, or a member of the schema's owning team may call this; others get `AccessDenied`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-schema-write-update", "metadata": { "sidebarTitle": "Update mapping schema" @@ -9890,6 +10252,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9918,12 +10283,12 @@ "post": { "operationId": "scheduleCreate", "summary": "Create schedule", - "description": "Create a new on-call schedule (escalation rule schedule).", + "description": "Create an on-call schedule with its rotation layers and shift notification settings.", "tags": [ "On-call/Schedules" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Schedules Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Schedules Manage** (`on-call`) |\n\n## Usage\n\n- `schedule_name` (or the legacy `name`) is required, at most 40 characters, and must be unique in the account. `description` is at most 500 characters.\n- `time_zone` anchors every wall-clock rule of the schedule (handoff time, restriction windows, weekdays, fixed-time notifications) and cannot be changed later. When omitted, the schedule is evaluated in `Asia/Shanghai` and `time_zone` reads back as an empty string.\n- Layer times can be sent either as numbers (`layer_start`, `handoff_time`, `restrict_periods`, …) or as wall-clock strings (`starts_at`, `ends_at`, `handoff`, `restricts_wall`); wall-clock fields win and are converted in the schedule's time zone.\n- Creating more schedules than the account's plan allows is rejected with `NoLicense`.\n- Use `/schedule/preview` to check the resulting shifts before saving.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/schedules/schedule-create", "metadata": { "sidebarTitle": "Create schedule" @@ -9964,6 +10329,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -9982,6 +10350,7 @@ "schedule_name": "Production On-Call", "description": "Primary on-call rotation for the production team", "team_id": 4291079133131, + "time_zone": "Asia/Shanghai", "layers": [ { "layer_name": "Layer 1", @@ -10061,12 +10430,12 @@ "post": { "operationId": "insightByChannel", "summary": "Get channel insight", - "description": "Return insight metrics aggregated by channel.", + "description": "Return incident and alert metrics grouped by channel, one row per channel per time bucket.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- One row per channel per time bucket. `responder_ids` and `incident_ids` are ignored.\n- Incidents are counted by creation time. Rows are sorted by `ts` from newest to oldest, and a bucket (or dimension value) with no incidents produces no row — missing rows mean zero. `split_hours: true` returns up to three rows per bucket, one per `hours` value.\n- `total_alert_cnt`, `total_alert_event_cnt` and `noise_reduction_pct` honor only the time range, team, channel and severity filters; `query`, `labels`, `fields` and the duration filters apply to incident metrics only.\n- Members who are neither the account owner nor an admin only get data from channels they can access; other channels are silently excluded.\n- With `is_my_team: true`, `team_ids` is narrowed to the caller's teams; a caller who belongs to no team gets an empty result.", "href": "/en/api-reference/on-call/analytics/insight-by-channel", "metadata": { "sidebarTitle": "Get channel insight" @@ -10134,6 +10503,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10165,12 +10537,12 @@ "post": { "operationId": "channelDelete", "summary": "Delete channel", - "description": "Delete a channel. Only a `disabled` channel can be deleted; all of its escalation, silence, drop and inhibit rules are deleted with it. The call fails when an integration route still references the channel.", + "description": "Delete a disabled channel together with its rules and channel-exclusive integrations.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` channel can be deleted; any other status returns `InvalidParameter`.\n- If a shared integration's routing rule still targets the channel (in a case or the default branch), the call returns HTTP 400 with `error.code` `ReferenceExist` and the referencing integrations in `data.refs`. Remove the channel from those routes with `POST /route/upsert` first.\n- All escalation, silence, drop, inhibit and subscribe rules of the channel and its channel-exclusive integrations are deleted. The channel itself is soft-deleted: `POST /channel/info` still returns it with `status` `deleted`.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-delete", "metadata": { "sidebarTitle": "Delete channel" @@ -10209,6 +10581,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10235,12 +10610,12 @@ "post": { "operationId": "channelUnsubscribeRuleCreate", "summary": "Create drop rule", - "description": "Create a drop rule to filter out unwanted alerts before they become incidents.", + "description": "Create a drop rule that discards matching alert events before any alert or incident is created.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Drop rules are checked first, before silence and inhibit rules. An event matching any enabled drop rule is discarded: no alert, incident or notification is produced.\n- Without `filters`, or with an empty list, the rule matches nothing.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-unsubscribe-rule-create", "metadata": { "sidebarTitle": "Create drop rule" @@ -10270,7 +10645,7 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "rule_id": "69db2f6ba0fe7db6448b1505", - "rule_name": "Test drop rule" + "rule_name": "Drop test environment alerts" } } } @@ -10282,6 +10657,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10322,12 +10700,12 @@ "post": { "operationId": "channelInhibitRuleUpdate", "summary": "Update inhibit rule", - "description": "Update an existing inhibit rule configuration.", + "description": "Replace the configuration of an existing inhibit rule.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Full replacement: omitted `source_filters` and `target_filters` become empty, an omitted `is_directly_discard` becomes `false`, and an omitted `description` becomes empty.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-inhibit-rule-update", "metadata": { "sidebarTitle": "Update inhibit rule" @@ -10366,6 +10744,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10397,12 +10778,12 @@ "post": { "operationId": "alert-write-merge", "summary": "Merge alerts into an incident", - "description": "Associate one or more alerts with an existing incident. If a source alert previously belonged to a different incident and that incident becomes empty after the merge, it will be automatically closed.", + "description": "Move one or more alerts into an existing incident and close source incidents left empty.", "tags": [ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- All `alert_ids` and the `incident_id` must belong to the caller's account.\n- Optionally set `title` and `owner_id` to update the target incident at the same time.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Every `alert_ids` entry and the `incident_id` must belong to the account; an unknown ID returns `InvalidParameter`.\n- Alerts already in the target incident are skipped. A source incident left with no alerts is closed.\n- `title` and `owner_id` update the target incident only when they differ from its current values.\n- Only one incident change runs per account at a time; a concurrent call returns `RequestTooFrequently`.", "href": "/en/api-reference/on-call/alerts/alert-write-merge", "metadata": { "sidebarTitle": "Merge alerts into an incident" @@ -10422,7 +10803,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/components/schemas/EmptyResponse" + "$ref": "#/components/schemas/EmptyObject" } } } @@ -10441,6 +10822,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10470,12 +10854,12 @@ "post": { "operationId": "statusPageChangeTimelineUpdate", "summary": "Update event timeline entry", - "description": "Update a timeline entry for a status page event.", + "description": "Edit the time or description of a status page event timeline entry.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- Only `at_seconds` and `description` can be edited; an entry's status and component changes are fixed.\n- Pass at least one of `at_seconds` (greater than 0) or a non-empty `description`; otherwise the call returns `InvalidParameter`.\n- `at_seconds` must stay between the previous and next entries; editing the first entry also moves the event start time.\n- Editing the latest entry's description also updates the event description. No subscriber notification is sent.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-change-timeline-update", "metadata": { "sidebarTitle": "Update event timeline entry" @@ -10514,6 +10898,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10544,12 +10931,12 @@ "post": { "operationId": "incidentReopen", "summary": "Reopen incident", - "description": "Reopen a previously resolved incident.", + "description": "Reopen closed incidents and dispatch them again from the first escalation level.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Every incident must be `Closed`; otherwise the whole call fails with `InvalidParameter`.\n- Reopened incidents return to `Triggered`, with `ack_time`, `close_time`, `closer_id`, and every responder's acknowledgement reset.\n- Each incident is reassigned to its previous assignment target starting at the first escalation level, with `assigned_to.type` set to `reopen`.\n- Returns `RequestTooFrequently` while another resolve, reopen, merge, comment, or delete is running in the same account; retry after a short delay.", "href": "/en/api-reference/on-call/incidents/incident-reopen", "metadata": { "sidebarTitle": "Reopen incident" @@ -10588,6 +10975,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10622,7 +11012,7 @@ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- To mention a member, embed a markdown link in `comment` in the form `[@Display Name](flashduty://ref/member/)`. Mentioned members receive a dedicated personal notification, which is not affected by `mute_reply`.\n- Plain `@name` text without the link syntax does not create a mention.\n- The server rewrites each mention's display label to the member's canonical name.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- To mention a member, embed a markdown link in `comment` in the form `[@Display Name](flashduty://ref/member/)`. Mentioned members receive a dedicated personal notification, which is not affected by `mute_reply`.\n- Plain `@name` text without the link syntax does not create a mention.\n- The server rewrites each mention's display label to the member's canonical name.\n- Returns `RequestTooFrequently` while another resolve, reopen, merge, comment, or delete is running in the same account; retry after a short delay.", "href": "/en/api-reference/on-call/incidents/incident-comment", "metadata": { "sidebarTitle": "Add comment to incident" @@ -10661,6 +11051,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10696,7 +11089,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- The response is a CSV file with `Content-Disposition: attachment` header.\n- The CSV header row matches the schema's source and result labels in order.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **60 requests/minute**; **3 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) or **Mappings Read** (`on-call`) or **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- The response is a CSV stream (`Content-Type: application/octet-stream`), not JSON. The file name in `Content-Disposition` is the schema name with spaces replaced by `_`.\n- The first row lists `source_labels` followed by `result_labels`; each following row is one data row, most recently written first.\n- The schema must exist and not be deleted; otherwise a JSON `InvalidParameter` error is returned.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-data-read-download", "metadata": { "sidebarTitle": "Download mapping data as CSV" @@ -10712,7 +11105,7 @@ "format": "binary", "description": "CSV file stream (`Content-Type: application/octet-stream`, `Content-Disposition: attachment; filename=.csv`). The header row lists the schema's source_labels followed by result_labels in order; each subsequent row is one mapping document." }, - "example": "host,owner,team\nserver01,alice,sre\nserver02,bob,backend\n" + "example": "host,owner,team,service\nserver01,alice,sre,api\n" } } }, @@ -10722,6 +11115,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10748,12 +11144,12 @@ "post": { "operationId": "channelUnsubscribeRuleList", "summary": "List drop rules", - "description": "List drop rules for a channel.", + "description": "List a channel's drop rules, oldest first.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- An unknown `channel_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/channel-unsubscribe-rule-list", "metadata": { "sidebarTitle": "List drop rules" @@ -10817,6 +11213,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10843,12 +11242,12 @@ "post": { "operationId": "routeList", "summary": "List routing rules", - "description": "Return routing rules for the specified integrations. Integrations without a configured rule are omitted from the response.", + "description": "Return the routing rules of several shared integrations in one call.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Integrations without a routing rule are omitted from `items`.\n- Every ID must be an existing shared integration; a single unknown or channel-exclusive ID fails the whole call with `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/route-list", "metadata": { "sidebarTitle": "List routing rules" @@ -10922,6 +11321,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -10951,12 +11353,12 @@ "post": { "operationId": "channelList", "summary": "List channels", - "description": "List channels accessible to the current user with optional filters.", + "description": "List the channels visible to the caller, with filters, sorting and pagination.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Without filters, every channel in the account is returned except private channels the caller cannot access. Deleted channels are never returned.\n- Setting both `is_my_team` and `is_my_starred` to `true` returns `InvalidParameter`. `is_my_managed` takes precedence over both. With `is_my_managed` or `is_my_team`, `team_ids` is ignored.\n- With `is_brief: true`, items carry only `channel_id`, `channel_name`, `description`, `status` and `is_starred`, and all matches are returned in one page.\n- Always pass `p`. When it is omitted the first page is returned, but `has_next_page` is then `true` whenever anything matches.", "href": "/en/api-reference/on-call/channels/channel-list", "metadata": { "sidebarTitle": "List channels" @@ -11005,6 +11407,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11034,12 +11439,12 @@ "post": { "operationId": "channelEscalateRuleCreate", "summary": "Create escalation rule", - "description": "Create an escalation rule defining who gets notified and when during an incident.", + "description": "Create an escalation rule that decides who is notified about a channel's incidents, and how.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Rules are evaluated in ascending `priority`. The first enabled rule whose `time_filters` and `filters` match a new incident takes it; later rules are skipped. Omit `priority` to place the rule after all existing ones.\n- `template_id` must be an existing notification template, every member in `person_ids` must exist and every team in `team_ids` must have members; otherwise `InvalidParameter`.\n- The new rule is `enabled`.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-create", "metadata": { "sidebarTitle": "Create escalation rule" @@ -11069,7 +11474,7 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "rule_id": "69db2f72a0fe7db6448b1506", - "rule_name": "Test escalation rule" + "rule_name": "On-call escalation" } } } @@ -11081,6 +11486,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11126,12 +11534,12 @@ "post": { "operationId": "channelUpdate", "summary": "Update channel", - "description": "Update an existing channel's configuration and settings.", + "description": "Update a channel's settings; only the fields present in the request are changed.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Omitted or `null` fields keep their current value. `group`, `flapping` and `event_group` each replace the whole stored object.\n- Pass `managing_team_ids: []` to remove all managing teams.\n- `auto_resolve_mode` is applied only together with `auto_resolve_timeout`; when `auto_resolve_timeout` is sent without `auto_resolve_mode`, the mode resets to `trigger`.\n- Setting `is_external_report_enabled` to `true` generates a new `external_report_token` on every call and the previous token stops working; `false` clears the token.\n- A `channel_name` used by another channel returns `InvalidParameter`; `group.method` `p` or `i` without the matching license returns `NoLicense`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-update", "metadata": { "sidebarTitle": "Update channel" @@ -11172,6 +11580,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11187,7 +11598,7 @@ "$ref": "#/components/schemas/UpdateChannelRequest" }, "example": { - "channel_id": 1001, + "channel_id": 3521074710131, "channel_name": "Production Alerts (v2)", "description": "Updated description" } @@ -11200,12 +11611,12 @@ "post": { "operationId": "channelEnable", "summary": "Enable channel", - "description": "Enable a channel to resume incident routing. Only a `disabled` channel can be enabled.", + "description": "Enable a disabled channel so it processes incoming alert events again.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` channel can be enabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-enable", "metadata": { "sidebarTitle": "Enable channel" @@ -11244,6 +11655,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11270,12 +11684,12 @@ "post": { "operationId": "channelEscalateRuleDelete", "summary": "Delete escalation rule", - "description": "Delete an escalation rule. Only a `disabled` rule can be deleted.", + "description": "Delete a disabled escalation rule so it no longer appears in the channel's rule list.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` rule can be deleted; any other status returns `InvalidParameter`.\n- The rule is soft-deleted: it disappears from the list, but `POST /channel/escalate/rule/info` still returns it with `status` `deleted`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-escalate-rule-delete", "metadata": { "sidebarTitle": "Delete escalation rule" @@ -11314,6 +11728,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11341,12 +11758,12 @@ "post": { "operationId": "mapping-api-write-delete", "summary": "Delete mapping API", - "description": "Delete a mapping API. Deletion is blocked if the API is referenced by any enrichment rule.", + "description": "Soft-delete a mapping API; refused while an enrichment rule uses it.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- If the API is still referenced, the response returns HTTP 400 with a `refs` list.\n- Only the API creator, account admin, or team member can delete the API.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- The mapping API is soft-deleted (`status` becomes `deleted`) and enrichment rules stop calling it.\n- If an integration's enrichment rule uses it (`mapping_type` = `api`), the call returns HTTP 400 `ReferenceExist` with `data.refs` listing up to 20 integrations (`kind` = `integration`).\n- An unknown `api_id` returns `InvalidParameter`.\n- Only an account admin, the mapping API creator, or a member of the mapping API's owning team may call this; others get `AccessDenied`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-api-write-delete", "metadata": { "sidebarTitle": "Delete mapping API" @@ -11385,6 +11802,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11411,12 +11831,12 @@ "post": { "operationId": "channelInhibitRuleList", "summary": "List inhibit rules", - "description": "List all inhibit rules configured for a channel.", + "description": "List a channel's inhibit rules, oldest first.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- An unknown `channel_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/channel-inhibit-rule-list", "metadata": { "sidebarTitle": "List inhibit rules" @@ -11457,7 +11877,7 @@ "key": "severity", "oper": "IN", "vals": [ - "Info" + "Critical" ] } ] @@ -11474,8 +11894,8 @@ ] ], "equals": [ - "data_source_id", - "labels._account_id" + "labels.cluster", + "labels.service" ], "is_directly_discard": false, "status": "enabled", @@ -11496,6 +11916,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11527,7 +11950,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **20 requests/minute**; **2 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- The request must use `Content-Type: multipart/form-data`. The file field name is `file` and `schema_id` is a query parameter.\n- CSV header row must include all source and result label names.\n- Maximum file size: 100 MB.\n- By default the schema's existing data is truncated before import. Pass query param `do_not_truncate_first=TRUE` to append instead.\n- Duplicate source label value combinations in the CSV cause a 400 error.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **60 requests/minute**; **3 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- Send `multipart/form-data` with the CSV in the `file` field; `schema_id` and `do_not_truncate_first` are query parameters. The file may be at most 100 MB.\n- The first CSV row is the header and must contain every source and result label; other columns are dropped. Values longer than 2,048 bytes are rejected, and byte-order marks are stripped. A file with no data rows returns `InvalidParameter`.\n- By default all existing rows are deleted before the import. With `do_not_truncate_first=TRUE` existing rows are kept and rows with the same source label values are replaced.\n- Rows with the same source label values are merged; the later row wins.\n- The schema row limit (10,000 rows by default, higher for some accounts) is checked against the row count after the import; exceeding it returns `InvalidParameter`.\n- Rows are written in batches of 100. If a batch fails, the truncation and the batches before it stay applied.\n- The schema must exist and not be deleted; otherwise `InvalidParameter`.\n- Only an account admin, the schema creator, or a member of the schema's owning team may call this; others get `AccessDenied`.\n- Data writes to one schema (upsert, delete, truncate, CSV upload) run one at a time; a call made while another is running returns `RequestTooFrequently`.", "href": "/en/api-reference/on-call/alert-enrichment/mapping-data-write-upload", "metadata": { "sidebarTitle": "Upload mapping data via CSV" @@ -11566,6 +11989,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11629,7 +12055,7 @@ "On-call/Alerts" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) |\n\n## Usage\n\n- `alert_id` is an ObjectID hex string returned by `POST /alert/list` or `POST /alert-event/list`.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Incidents Read** (`on-call`) or **Incidents Manage** (`on-call`) |\n\n## Usage\n\n- `alert_id` is an ObjectID hex string returned by `POST /alert/list` or `POST /alert-event/list`.\n- An `alert_id` not found in the account returns `InvalidParameter`.", "href": "/en/api-reference/on-call/alerts/alert-read-info", "metadata": { "sidebarTitle": "Get alert detail" @@ -11675,6 +12101,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11701,12 +12130,12 @@ "post": { "operationId": "incidentAssign", "summary": "Assign incident", - "description": "Dispatch an incident to a specific escalation level or responder.", + "description": "Reassign incidents to members or an escalation rule, replacing the current responders.", "tags": [ "On-call/Incidents" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Incidents Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Incidents Manage** or **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Responders not in the new target are removed; responders who stay keep their acknowledgement. If none of the remaining responders has acknowledged, the incident returns to `Triggered`. Any snooze is cleared.\n- When `assigned_to` sets none of `person_ids`, `escalate_rule_id`, and `emails`, the server re-runs the channel's escalation rule matching instead.\n- Closed incidents are skipped without error.\n- The server fills `assigned_at`, `id`, and `escalate_rule_name`, and derives `type` when it is omitted.", "href": "/en/api-reference/on-call/incidents/incident-assign", "metadata": { "sidebarTitle": "Assign incident" @@ -11745,6 +12174,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11777,12 +12209,12 @@ "post": { "operationId": "channelInhibitRuleDisable", "summary": "Disable inhibit rule", - "description": "Disable an inhibit rule without deleting it. Only an `enabled` rule can be disabled.", + "description": "Disable an inhibit rule without deleting it.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only an `enabled` rule can be disabled; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-inhibit-rule-disable", "metadata": { "sidebarTitle": "Disable inhibit rule" @@ -11821,6 +12253,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11848,12 +12283,12 @@ "post": { "operationId": "calendarInfo", "summary": "Get calendar info", - "description": "Return details of a service calendar.", + "description": "Return the details of one service calendar of the account by its ID.", "tags": [ "On-call/Calendars" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- An unknown `cal_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/calendars/calendar-info", "metadata": { "sidebarTitle": "Get calendar info" @@ -11914,6 +12349,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -11940,12 +12378,12 @@ "post": { "operationId": "channelSilenceRuleCreate", "summary": "Create silence rule", - "description": "Create a silence rule to suppress notifications matching specified conditions.", + "description": "Create a silence rule that mutes or drops matching alert events during a time window.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Set exactly one of `time_filter` (one-off window) or `time_filters` (recurring windows), and give `filters` at least one condition; otherwise `InvalidParameter`.\n- Each incoming event is checked against drop rules first, then silence rules, then inhibit rules. The first enabled silence rule whose window covers the current time and whose `filters` match is applied.\n- With `from_incident_id`, only one enabled silence rule may exist per incident; creating a second returns `InvalidParameter`.\n- An unknown `channel_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-silence-rule-create", "metadata": { "sidebarTitle": "Create silence rule" @@ -11975,7 +12413,7 @@ "request_id": "01HK8XQE3Z7JM2NTFQ5YJ8P9R4", "data": { "rule_id": "69db2f66a0fe7db6448b1503", - "rule_name": "Test silence rule" + "rule_name": "Maintenance window silence" } } } @@ -11987,6 +12425,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12031,12 +12472,12 @@ "post": { "operationId": "channelSilenceRuleDelete", "summary": "Delete silence rule", - "description": "Delete a silence rule. Only a `disabled` rule can be deleted.", + "description": "Delete a disabled silence rule so it no longer appears in the channel's rule list.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Channels Manage** (`on-call`) |\n\n## Usage\n\n- Only a `disabled` rule can be deleted; any other status returns `InvalidParameter`.\n- An unknown `channel_id` or `rule_id` returns `InvalidParameter`.\n- The caller must also be able to edit the channel: the account owner or an admin, the channel creator, or a member of its managing teams (of its owning team when `managing_team_ids` is empty). Otherwise the call returns `AccessDenied`.\n- Every call is recorded in the account audit log.", "href": "/en/api-reference/on-call/channels/channel-silence-rule-delete", "metadata": { "sidebarTitle": "Delete silence rule" @@ -12075,6 +12516,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12107,7 +12551,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **2 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Requires the On-call Professional plan; other accounts get `AccessDenied`.\n- Runs asynchronously: the call checks the API key and source page, returns `job_id`, and the import continues in the background; poll `GET /status-page/migration/status`.\n- Only one migration job per account can run at a time; starting another returns `InvalidParameter`.\n- Creates a public status page with email subscription enabled; running it again for the same source page reuses the page created earlier.\n- Imports sections (from component groups), components, past incidents and maintenances, and incident templates; template failures are recorded in `progress.warnings` and do not fail the job.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-migrate-structure", "metadata": { "sidebarTitle": "Migrate status page structure" @@ -12148,6 +12592,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12180,7 +12627,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Status Pages Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **30 requests/minute**; **2 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Requires the On-call Professional plan; other accounts get `AccessDenied`.\n- Runs asynchronously and returns `job_id`; poll `GET /status-page/migration/status`. Only one migration job per account can run at a time.\n- Run it after `POST /status-page/migrate-structure` for the same source page: component subscriptions are mapped to the components that migration created, and a subscriber whose components cannot be mapped is subscribed to all components.\n- Non-email, quarantined, and address-less subscribers are skipped and counted in `progress.subscribers_skipped`; recipients already subscribed on the target page are left unchanged.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-migrate-email-subscribers", "metadata": { "sidebarTitle": "Migrate email subscribers" @@ -12221,6 +12668,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12249,12 +12699,12 @@ "post": { "operationId": "template-write-create", "summary": "Create a template", - "description": "Create a new notification template.", + "description": "Create a notification template with per-channel message sources.", "tags": [ "On-call/Notification templates" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Templates Manage** (`on-call`) |\n\n## Usage\n\n- `template_name` must be unique within the account; duplicates return `InvalidParameter`.\n- The server validates every non-empty channel template by rendering it against a mock incident — a syntactic error in any channel fails the whole request with `InvalidParameter`.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Templates Manage** (`on-call`) |\n\n## Usage\n\n- Requires the Pro plan or higher; otherwise `NoLicense`.\n- `template_name` must be unique among the account's non-deleted templates and must not equal the built-in preset template's name in any supported language; otherwise `InvalidParameter`.\n- Every non-empty channel source is test-rendered against a mock incident; a template error in any channel fails the whole request with `InvalidParameter`. With `wecom_markdown_v2_enabled` = `true`, the rendered `wecom` content must be at most 4,096 bytes.\n- Channels left empty use the built-in preset content when notifications are sent.\n- A non-zero `team_id` must be an existing team; otherwise `InvalidParameter`.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/notification-templates/template-write-create", "metadata": { "sidebarTitle": "Create a template" @@ -12296,6 +12746,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12314,8 +12767,8 @@ "team_id": 0, "template_name": "Prod incident default", "description": "Default template for production incidents.", - "email": "Incident {{ .IncidentName }} on {{ .Severity }}", - "sms": "[Flashduty] {{ .IncidentName }} — {{ .Severity }}" + "email": "Incident {{.Title}} is {{.IncidentSeverity}}", + "sms": "[Flashduty] {{.Title}} - {{.IncidentSeverity}}" } } } @@ -12326,12 +12779,12 @@ "post": { "operationId": "routeInfo", "summary": "Get routing rule detail", - "description": "Retrieve the routing rule configuration for a specific integration. Returns null when the integration has no routing rule configured.", + "description": "Return the routing rule of one shared integration.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- When the integration has no routing rule, the response carries only `request_id`, with no `data` field.\n- A channel-exclusive or unknown `integration_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/route-info", "metadata": { "sidebarTitle": "Get routing rule detail" @@ -12416,6 +12869,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12447,7 +12903,7 @@ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- Returns `null` if no enrichment rules have been configured for the integration.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Integrations Read** (`on-call`) or **Integrations Manage** (`on-call`) |\n\n## Usage\n\n- `integration_id` must be an existing integration of the account; otherwise `InvalidParameter`.\n- Returns `data: null` when the integration has no rule set.", "href": "/en/api-reference/on-call/alert-enrichment/enrichment-read-info", "metadata": { "sidebarTitle": "Get enrichment rules" @@ -12504,6 +12960,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12530,12 +12989,12 @@ "post": { "operationId": "channelInfo", "summary": "Get channel detail", - "description": "Retrieve detailed information for a specific channel.", + "description": "Return one channel's full configuration with counts of its active incidents from the last 30 days.", "tags": [ "On-call/Channels" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Deleted channels are still returned, with `status` `deleted`.\n- A private channel (`is_private: true`) returns `AccessDenied` unless the caller is the account owner or an admin, its creator, or a member of its owning or managing teams.\n- `team_name`, `creator_name` and `is_starred` are not returned here; use `POST /channel/list` for them.\n- An unknown `channel_id` returns `InvalidParameter`.", "href": "/en/api-reference/on-call/channels/channel-info", "metadata": { "sidebarTitle": "Get channel detail" @@ -12579,6 +13038,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12610,7 +13072,7 @@ "On-call/Notification templates" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Templates Read** (`on-call`) or **Templates Manage** (`on-call`) |\n\n## Usage\n\n- Pagination defaults to page 1 with 20 rows. The response's `has_next_page` tells you whether another page exists without needing a separate count request.\n- When `is_my_team` is `true`, `team_ids` is ignored.", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Channels Read** (`on-call`) or **Channels Manage** (`on-call`) or **Templates Read** (`on-call`) or **Templates Manage** (`on-call`) |\n\n## Usage\n\n- The first page always starts with the built-in preset template (`template_id` `6321aad26c12104586a88916`), whatever the filters; it is also counted in `total`.\n- Results are sorted by `orderby` (default `created_at`), newest first unless `asc` is `true`. Soft-deleted templates are excluded.\n- `is_my_team: true` limits results to templates of the caller's teams; with `team_ids` also sent, only the teams in both lists are kept. If that intersection is empty, no team filter is applied and templates of all teams are returned. If the caller belongs to no team, the response is empty (`total` = 0, no preset).\n- `query` is a case-insensitive regular expression on `template_name`; an invalid expression is matched as literal text.", "href": "/en/api-reference/on-call/notification-templates/template-read-list", "metadata": { "sidebarTitle": "List templates" @@ -12648,8 +13110,8 @@ "template_id": "6605a1b2c3d4e5f6a7b8c9d0", "template_name": "Prod incident default", "description": "Default template for production incidents.", - "email": "Incident {{ .IncidentName }} on {{ .Severity }}", - "sms": "[Flashduty] {{ .IncidentName }} — {{ .Severity }}", + "email": "Incident {{.Title}} is {{.IncidentSeverity}}", + "sms": "[Flashduty] {{.Title}} - {{.IncidentSeverity}}", "voice": "", "dingtalk": "", "wecom": "", @@ -12662,6 +13124,14 @@ "telegram": "", "slack": "", "zoom": "", + "wecom_markdown_v2_enabled": false, + "feishu_app_card_v2_table_enabled": false, + "feishu_app_card_v2_preserve_blank_lines": false, + "feishu_app_war_room_enabled": false, + "dingtalk_app_war_room_enabled": false, + "slack_app_war_room_enabled": false, + "incident_card_closed_action_apps": [], + "incident_card_hidden_fields": {}, "status": "enabled", "creator_id": 80011, "updated_by": 80011, @@ -12680,6 +13150,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12710,12 +13183,12 @@ "post": { "operationId": "insightByResponder", "summary": "Get responder insight", - "description": "Return insight metrics aggregated by responder.", + "description": "Return per-responder incident handling metrics, one row per responder per time bucket.", "tags": [ "On-call/Analytics" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Analytics Read** (`on-call`) |\n\n## Usage\n\n- One row per responder per time bucket; `responder_ids` limits which responders are returned. `seconds_to_close_from`/`seconds_to_close_to` and `incident_ids` are ignored.\n- Incidents are counted by creation time. Rows are sorted by `ts` from newest to oldest, and a bucket (or dimension value) with no incidents produces no row — missing rows mean zero. `split_hours: true` returns up to three rows per bucket, one per `hours` value.\n- Members who are neither the account owner nor an admin only get data from channels they can access; other channels are silently excluded.\n- With `is_my_team: true`, `team_ids` is narrowed to the caller's teams; a caller who belongs to no team gets an empty result.", "href": "/en/api-reference/on-call/analytics/insight-by-responder", "metadata": { "sidebarTitle": "Get responder insight" @@ -12774,6 +13247,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12805,12 +13281,12 @@ "get": { "operationId": "statusPageChangeList", "summary": "List status page events", - "description": "List status page events for console management. Unlike the public display endpoints, the response includes hidden components.", + "description": "List the incidents or maintenances of a status page by status and time window, including hidden components.", "tags": [ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Returns every matching event in one response (no pagination), sorted by `start_at_seconds`, newest first.\n- Without `start_at_seconds` and `end_at_seconds`, the time window is unbounded.", "href": "/en/api-reference/on-call/status-pages/status-page-change-list", "metadata": { "sidebarTitle": "List status page events" @@ -12901,6 +13377,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -12982,7 +13461,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |", + "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- Returns all non-terminal events of the given type in one response, newest first: `investigating`/`identified`/`monitoring` incidents, or `scheduled`/`ongoing` maintenances.", "href": "/en/api-reference/on-call/status-pages/status-page-change-active-list", "metadata": { "sidebarTitle": "List active status page events" @@ -13059,6 +13538,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -13102,7 +13584,7 @@ "On-call/Status pages" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | None — any valid `app_key` can call this operation |\n\n## Usage\n\n- The `draft` payload is stored verbatim (up to 64 KB); the console publish form reads it back to prefill the event.\n- A draft lives for 30 days and is consumed exactly once when the event is published.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Status Pages Events Manage** (`on-call`) |\n\n## Usage\n\n- The `draft` payload is stored verbatim (up to 64 KB); the console publish form reads it back to prefill the event.\n- `draft.page_id` must be a page of the caller's account, every component in `draft.affected_components` must exist on it, and a `draft.change_id` greater than 0 must be an event of the same `type`.\n- Publish the draft by passing `draft_id` to `POST /status-page/change/create` (new event) or `POST /status-page/change/timeline/create` (update to `draft.change_id`); a draft can be published only once.\n- A draft is deleted 30 days after creation, whether or not it was published.\n- Every call is recorded in the account audit log. Don't put secrets in request fields.", "href": "/en/api-reference/on-call/status-pages/status-page-draft-create", "metadata": { "sidebarTitle": "Create status page draft" @@ -13144,6 +13626,9 @@ "401": { "$ref": "#/components/responses/Unauthorized" }, + "403": { + "$ref": "#/components/responses/Forbidden" + }, "429": { "$ref": "#/components/responses/TooManyRequests" }, @@ -13183,12 +13668,12 @@ "post": { "operationId": "mapping-api-write-create", "summary": "Create mapping API", - "description": "Create a new external HTTP API endpoint used to enrich alerts via HTTP lookup.", + "description": "Register an external HTTP API that enrichment rules call to look up alert labels.", "tags": [ "On-call/Alert enrichment" ], "x-mint": { - "content": "## Restrictions\n\n| Aspect | Value |\n| ------ | ----- |\n| Rate limits | **1,000 requests/minute**; **50 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- `url` must start with `http://` or `https://` and cannot resolve to an internal IP (in SaaS mode).\n- `timeout` is the HTTP read timeout in seconds (1–3, default 2).\n- `retry_count` is the number of retries on failure (0–1, default 0).\n- Headers with security-sensitive names (e.g. `authorization`, `cookie`) are rejected in SaaS mode.\n- An account can have at most 50 mapping APIs.\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 | **300 requests/minute**; **20 requests/second** per account |\n| Permissions | **Mappings Manage** (`on-call`) |\n\n## Usage\n\n- An enrichment rule with `mapping_type` = `api` sends `POST ` with the configured `headers` and the JSON body `{\"result_label_keys\": [...], \"event\": {...}}` (the alert event). The API must answer HTTP 200 with `{\"result_labels\": {\"